Derived from Ubuntu Security Podcast episode 83 7/2020:
+/- LSM == Linux Security Module inside the kernel.

Stacking == using multiple security modules in same system.

As of 5.8 kernel, stacking is limited, but this is being changed.

Current (5.8) stacking rules:
Major modules (SELinux, AppArmor, Smack): can't stack with another major module, because they all try to attach their security data blobs to the same hooks inside the kernel.
Minor modules (Yama, LoadPin, Lockdown): can stack.
Some modules might be allowed to stack but not make sense to stack on each other, they conflict or duplicate.

A major module implements MAC, with configurable policies loaded from user space. So it makes sense to have only one major module.

A minor module typically only contains flags to enable/disable options, and needs less context.

Shaun Ruffell's "A Brief Tour of Linux Security Modules"
Wikipedia's "Linux Security Modules"'s "Linux Security Module Usage"
Cloudflare article about "LSM BPF"
"cat /sys/kernel/security/lsm" to see list of current modules

Network Control and Firewalls

This section is for tools that generally run unattended. For tools used by a person, see the Network Monitoring section.

Some terms:

Ubuntu's "DoINeedAFirewall"
Adrian Grigorof's "Open Source Security Controls"

You can change your MAC address to any value, either for Wi-Fi or for wired Ethernet, via the Network or Network Manager application.


"Netfilter is the framework in the Linux kernel, which implements the rule and filters provided by the user, through an interface available to user called iptables."

GUFW and UFW (simplified UIs to use instead of iptables)

Coming in KDE: plasma-firewall, a GUI on top of multiple types of back-end firewalls such as ufw and firewalld.

  • /etc/hosts file:
    Purpose of /etc/hosts, from someone on reddit:
    "Functionally, it's just a way to say 'map this name to this IP address', like any other DNS resolution method. But it's useful for anything particular to your local machine. Typically it will at least include a mapping from localhost to, which can be useful for lots of things including local web development (bind your server to a local port and then just type 'localhost' in your browser). Also can use to override public domain names (temporarily, for debugging), or give friendly names to IP addresses (such as VPSs on cloud services)."

    MintGuide's "Hosts - change and manage the /etc/hosts file"
    hectorm / hBlock
    Wikipedia's "hosts (file)"
    "man 5 hosts"

  • iptables:
    "modinfo ip_tables"

    +/- There are 5 "tables": filter, nat, mangle, raw, security. We only care about the filter table, which has these built-in "chains" of rules: INPUT, FORWARD, OUTPUT. You can create new chains if you wish. Each rule ends with an action which can be: ACCEPT, DROP, LOG, or name of another chain. (There is more, but that's all we need to know.)

    To see how much traffic is passing through each section of rules in filter table, do "sudo iptables -L -v" (can reset counters via "sudo iptables -Z"). On my system, with Windscribe VPN active, after doing a bunch of downloading, that gives:
    Chain INPUT (policy ACCEPT 2005K packets, 2860M bytes)
     pkts bytes target     prot opt in     out     source               destination
    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination
    Chain OUTPUT (policy DROP 306 packets, 21425 bytes)
     pkts bytes target     prot opt in     out     source               destination
      486 75925 ACCEPT     all  --  any    any     anywhere   
     1104 72461 ACCEPT     all  --  any    any     anywhere   
        0     0 ACCEPT     all  --  any    any     anywhere   
     495K  860M ACCEPT     all  --  any    any     anywhere             localhost
     1339  139K ACCEPT     all  --  any    any     anywhere   
     1369  143K ACCEPT     all  --  any    any     anywhere   
     417K   55M ACCEPT     all  --  any    tun+    anywhere             anywhere
        0     0 ACCEPT     all  --  any    any     anywhere             localhost
     423K   78M ACCEPT     all  --  any    any     anywhere             89.238.nnn.nnn
    So my system is doing no routing ("FORWARDing"). And if no rule is matched, the packet gets DROPped if it is output, ACCEPTed if it is input.

    To block SSH connections from any address, do "sudo iptables -A INPUT -p tcp --dport ssh -j DROP". Can do the same with http and https if you're not running a web server.

    There is "ip6tables" which is separate but mostly has the same syntax as "iptables".

    There is a "conntrack" module which lets you do things such as "ctstate" in rules.

    To save changes so they survive across system restart, on Ubuntu-type systems, do "sudo apt install iptables-persistent", then turn off Windscribe VPN and firewall, then do "sudo su", and then "iptables-save >/etc/iptables/rules.v4" and "ip6tables-save >/etc/iptables/rules.v6".

    You can write commands such as "-P INPUT DROP" into a file such as "iptables.txt" and then run "sudo su" then "iptables-restore <iptable.txt"

    How-To Geek's "The Beginner's Guide to iptables, the Linux Firewall"
    Supriyo Biswas's "An In-Depth Guide to iptables, the Linux Firewall"
    Vivek Gite's "Iptables Netfilter Firewall Examples"
    Sagar Sharma's "The Beginner's Guide to IPTables (Linux Firewall) Commands"
    Mitchell Anicas's "Iptables Essentials: Common Firewall Rules and Commands"
    IP sets
    iptables-vis - visualise iptables chains

    I ran a bash file with commands:
    iptables -P INPUT DROP
    iptables -I INPUT -i lo -j ACCEPT
    iptables -I INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -P FORWARD DROP
    Ran Windscribe VPN client which resulted ("iptables -L") in:
    Chain INPUT (policy DROP)
    target     prot opt source               destination
    ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
    ACCEPT     all  --  anywhere             anywhere
    Chain FORWARD (policy DROP)
    target     prot opt source               destination
    Chain OUTPUT (policy DROP)
    target     prot opt source               destination
    ACCEPT     all  --  anywhere   
    ACCEPT     all  --  anywhere   
    ACCEPT     all  --  anywhere   
    ACCEPT     all  --  anywhere             localhost
    ACCEPT     all  --  anywhere   
    ACCEPT     all  --  anywhere   
    ACCEPT     all  --  anywhere             anywhere
    ACCEPT     all  --  anywhere             localhost
    ACCEPT     all  --  anywhere             89.238.nnn.nnn
    That anywhere-anywhere rule actually has "out=tun+" attached to it (can see that via "iptables -L -v"), so all that traffic goes through the VPN.

    Put DROP on all IPv6 chains; my ISP doesn't support IPv6.

    Ran a couple of net-testing apps on my phone (which is on my LAN), targeting my PC, and they show all ports blocked, no response to ping, no services offered.

    If you want to log packets that don't match any rule, and end up getting DROPed by the chain policy, add a rule at the END of the chain via a command such as "iptables -A FORWARD -m limit --limit 1/minute -j LOG".

    Default logfile for iptables is /var/log/kern.log;
    "sudo dmesg -T" command shows same log, with some useful coloring added.

    I would like to log/detect all applications that create output connections. But it seems this is very difficult to do in a human-readable way:
    Super User's "With Linux iptables, is it possible to log the process/command name that initiates an outbound connection?"
    Akkana's "Find out what processes are making network connections"

    You can get instantaneous snapshots (not cumulative logs) by running "ss -tp" or "netstat -A inet -p".

    To see IP address and other details about each network interface, run "ip -d address".

    I want to log any incoming attempts on protocols/ports I don't use.

    Found this: "You can add the --syn flag to make the rule match only packets with the SYN flag set, which is set only on new connection attempts."

    Maybe do this:
    "iptables -I INPUT -p tcp --dport ssh --syn -m limit --limit 1/minute -j LOG --log-prefix "Incoming SSH attempt ""
    Do similar for FTP, Telnet, HTTP, HTTPS.

    I didn't bother to make rules for TeamViewer (port 5938), Remote Desktop (port 3389), SMB (port 139), NFS (port 2049), VNC (port 5900), http-alt (port 8080), RTelnet (port 107), TFTP (port 69), Simple FTP (port 115), rsh (port 514), rsync (port 873), Telnet-TLS (port 992), PPTP (port 1723), SSDP (port 1900), CIFS (port 3020), UPnP (port 5000), Socks Proxy (port 1080), Microsoft-DS (port 445) attempts. You can go a little nuts with this stuff. I think I don't have listeners active for any of it, but it would be nice to log and drop the packets.

    But it turns out you can make one rule for multiple ports, so I made:
    "iptables -I INPUT -p tcp --match multiport --dports 5938,3389,139,2049,5900,8080,107,69,115,514,873,992,1723,1900,3020,5000 --syn -m limit --limit 1/minute -j LOG --log-prefix "Incoming suspicious port attempt ""
    Limit of 15 port numbers per rule; had to split it into two.

    If one of your rules logs incoming HTTP attempts, test it by putting address "localhost:80" into browser's address field, then looking in logs. Or test by running "curl localhost" on the CLI.

    If one of your rules logs incoming HTTPS attempts, test it by putting address "https://localhost" into browser's address field, then looking in logs. Or test by running "curl localhost:443" on the CLI.

    If your rules log incoming SSH and/or Telnet and/or FTP attempts, test them by running "ssh localhost" and/or "telnet localhost" and/or "ftp localhost" in CLI, then looking in logs. Or doing "curl localhost:22" and/or "curl localhost:23" and/or "curl localhost:21" in CLI, then looking in logs.

    But I want to drop the packets after logging them. So I did this:
    iptables -N I_LOG_DROP
    iptables -A I_LOG_DROP -m limit --limit 4/minute -j LOG --log-prefix "IPTABLES-I-LOG-DROP: " --log-level 6
    iptables -A I_LOG_DROP -j DROP
    iptables -P INPUT DROP
    iptables -A INPUT -p tcp --match multiport --dports 20,21,22,23,80,5938,3389,139,2049,5900,8080,107 --syn -j I_LOG_DROP
    iptables -A INPUT -p tcp --match multiport --dports 69,115,514,873,992,1723,1900,3020,5000 --syn -j I_LOG_DROP

    At some point, maybe it's easier to list the ports that should be open, instead of those that should be blocked. But maybe some high port numbers get opened dynamically.
    "iptables -I INPUT -p tcp --match multiport ! --dports 80,443 --syn -m limit --limit 1/minute -j LOG --log-prefix "Incoming suspicious port attempt ""

    Did this (in a shell script file):
    iptables -F
    iptables -Z
    iptables -N I_LOG_DROP
    iptables -A I_LOG_DROP -m limit --limit 4/minute -j LOG --log-prefix "IPTABLES-I-LOG-DROP: " --log-level 6
    iptables -A I_LOG_DROP -j DROP
    iptables -N O_LOG_DROP
    iptables -A O_LOG_DROP -m limit --limit 4/minute -j LOG --log-prefix "IPTABLES-O-LOG-DROP: " --log-level 6
    iptables -A O_LOG_DROP -j DROP
    iptables -P INPUT DROP
    iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i lo -j ACCEPT
    iptables -A INPUT -p tcp -m tcp --syn -j I_LOG_DROP
    # UDP 1194 for Proton VPN, UDP 5353 is multicast DNS / Avahi
    iptables -A INPUT -p udp --match multiport ! --dports 22,67,68,80,443,1194,5353 -j I_LOG_DROP
    iptables -P FORWARD DROP
    iptables -P OUTPUT ACCEPT
    # port 23189 used by SFTP
    iptables -A OUTPUT -p tcp --match multiport ! --dports ssh,http,https,23189 --syn -j O_LOG_DROP
    # UDP 1194 for Proton VPN, UDP 5037 when using Wireshark
    iptables -A OUTPUT -p udp --match multiport ! --dports 22,53,67,68,80,123,443,1194,1900,5037,5353,30000:64000 -j O_LOG_DROP

    The whole thing gets more complicated because your VPN probably does iptables stuff too. Windscribe VPN adds rules and changes chain policies. I had to have a big shell script to add rules before the VPN starts, then a small script to do a couple of tweaks after VPN has started.

    And the number of ports keeps growing and growing. Apps such as Firefox and torrent-client open lots of high port numbers. Most/all of them may be on localhost, so maybe you have to start wiring addresses into your rules. The whole thing just gets too complicated.

    If you see an iptables LOG line in /var/log/kern.log that doesn't show source and dest ports, but gives "PROTO=n", look up that protocol number in /etc/protocols.

    Do "sudo netstat -tulpn" to see what ports have listeners. (Also "sudo ss -tulp" or "sudo ss -tulp '! ( src or src [::1] )'" and "sudo lsof -i")

    Around this time, I mostly gave up with iptables. I think it was the wrong approach.
    Instead, concentrate on reducing and understanding the number of listeners you have. It doesn't matter if an incoming packet gets through iptables, as long as no process is listening on that port.

    Let the VPN do what it wants with iptables. Maybe do "sudo iptables -L -v" occasionally to see how much traffic is hitting each rule.

    I think it would be different with a server, running only a few services. There you could allow only 10 or so open ports.

    Maybe there are some "listeners" built into the protocol stack ? Turn off protocols you know you aren't using. Maybe do this to see unusual protocols:
    iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -i lo -j ACCEPT
    # assuming your INPUT chain policy is ACCEPT, put these at the end of the chain
    iptables -A INPUT -p tcp -j ACCEPT
    iptables -A INPUT -p udp -j ACCEPT
    iptables -A INPUT -p icmp -j ACCEPT
    iptables -A INPUT -m limit --limit 1/minute -j LOG --log-prefix "Incoming IPv4 protocol "

  • FireHOL:

    "FireHOL is a language (and a program to run it) which builds secure, stateful firewalls from easy to understand, human-readable configurations. ... FireHOL is an iptables firewall generator producing stateful iptables packet-filtering firewalls ..."

  • ufw and gufw:
    GUFW and UFW (simplified UIs to use instead of iptables).

    sudo ufw status verbose
    sudo ufw app list         # which apps installed a profile
    sudo ufw app info "CUPS"  # see an app's profile
    sudo systemctl enable ufw.service
    sudo systemctl start ufw.service
    sudo dmesg -T | grep UFW  # then look up PROTO= number in /etc/protocols
    less /etc/default/ufw
    less /etc/ufw/sysctl.conf
    sudo less /etc/gufw/gufw.cfg     # find which profile is in use
    sudo less /etc/gufw/Home.profile # see that profile
    sudo iptables -L -v              # see implementation of ufw/gufw rules

    UFW at least has the concept of "applications", but I don't know how that appears in GUFW.

    Francesco Galgani's "How to Use UFW"
    Virdo, Boucheron and Juell's "How To Set Up a Firewall with UFW on Debian 10"
    Vivek Gite's "How To Configure Firewall with UFW on Ubuntu 20.04 LTS"
    Jahid Onik's "How To Configure Firewall with UFW on Ubuntu"
    Linuxize's "How to Set Up a Firewall with UFW on Debian 10"
    Daniel Aleksandersen's "How to switch firewalls from FirewallD to UFW"

  • firewalld:
    LinuxTeck's "15 basic useful firewall-cmd commands in Linux"
    Brian Boucheron's "How To Set Up a Firewall Using firewalld on CentOS 8"
    Shashank Nandishwar Hegde's "An introduction to firewalld rules and scenarios"
    Evans Amoany's "How to configure a firewall on Linux with firewalld"
    LinuxCLoudVPS's "10 Useful firewall-cmd Commands in Linux"
    SoByte's "Linux Firewall FirewallD and iptables"
    Firewalld only controls inbound traffic, doesn't do outbound ?
    GUI for firewalld: firewall-config. Very detailed, a bit overwhelming.
    "sudo firewall-cmd --state"
    "sudo firewall-cmd --list-all"
    "sudo firewall-cmd --get-active-zones"
    "sudo firewall-cmd --get-default-zone"

    Avoid duelling firewalls. You can't run firewalld and ufw/gufw at the same time. firewalld and ufw both use iptables.
    "whereis -b -B /usr/bin /usr/sbin -f gufw ufw firewalld"

  • plasma-firewall:
    Coming in KDE: plasma-firewall, a GUI on top of multiple types of back-end firewalls such as ufw and firewalld.

  • Nftables:
    This is a replacement for iptables, ip6tables, arptables, and ebtables. It is a more procedural language, I think. Should avoid a lot of duplication that you can get in iptables rules, and scale better. Also combines IPv4 and IPv6 in one structure. Not supported by VPNs yet, I think. Still in development 11/2018, I think.

    Debian / wiki / nftables
    Nftables wiki
    Alistair Ross's "Hello nftables, Goodbye iptables"
    "apt show nftables"
    "sudo nft list tables"
    "sudo nft list ruleset | less"

    From someone on reddit:
    Here's how simple it is to get a sensible nftables ruleset in place:
    sudo apt install nftables
    # Use an example ruleset for a basic workstation
    sudo cp /usr/share/doc/nftables/examples/workstation.nft /etc/nftables.conf
    # Load that ruleset
    sudo nft -f /etc/nftables.conf
    sudo systemctl enable nftables
    Have a look at that config file, it's pretty short and all of the rules have comments explaining what they do. There's one rule in there commented out, which you can enable to open any local ports you might want to access from remote systems, e.g. SSH.

  • BPF (Berkeley Packet Filter; AKA cBPF) and eBPF:
    BPF programs are run in reaction to events, and run to completion. They're not constantly-running tasks.

    eBPF has been in the Linux kernel since version 3.18.

    Used to make a replacement for iptables and nftables, among many other things.

    Original BPF has a fairly small VM inside the kernel, and byte-code can be placed in it to do network processing.

    Relative to BPF, eBPF adds attaching code in many more places inside the kernel, adds a Just-In-Time compiler to native code (for some CPU architectures), and adds global state (in arrays, key-value pairs).
    Also has ability to jump out to user-land code, bypassing much of the standard network stack, for example, in cases where reduced features and higher performance make sense. Or go the other way: where there used to be a (costly) jump out to user-land, instead do the operation inside the kernel, in the VM.

    Wikipedia's "Berkeley Packet Filter"
    Filip Nikolovski's "TIL: eBPF is awesome"
    Kevin Dankwardt's "BPF For Observability: Getting Started Quickly"
    Andrew Klotz's "BPF intro: syscall counting"
    Matt Fleming's "A thorough introduction to eBPF"
    SoByte's "eBPF, a Linux kernel monitoring technology"
    SoByte's "Develop a Hello World level eBPF program from scratch using C"
    SoByte's "Things we need to know about eBPF"
    SoByte's "In-depth understanding of eBPF"
    Quentin Monnet's "Features of bpftool"
    eBPF - Introduction, Tutorials & Community Resources

    Brendan Gregg's "Learn eBPF Tracing: Tutorial and Examples"
    Brendan Gregg's "Linux Extended BPF (eBPF) Tracing Tools"
    Brendan Gregg's "Extended BPF - A new software type" (video)
    Hongli Lai's "Full-system dynamic tracing on Linux using eBPF and bpftrace"

    Azizi and Arbitman's "The Challenge with Deploying eBPF Into the Wild"
    iovisor / bcc
    iovisor / bcc / docs

    grep BPF "/boot/config-$(uname -r)"
    sudo bpftool feature probe kernel | less
    sudo apt install bpfcc-tools bcc-tools bpftrace bpftool
    sudo bpftool prog list
    sudo bpftool prog dump jited id 56
    sudo bps
    # Newer versions of bpftool will give PIDs in the
    # output of "sudo bpftool prog show".
    # See which processes have BPF file descriptors open:
    sudo bash
    for i in $(ps ax -o pid= ); do ls -l /proc/$i/fd|grep "bpf-prog" &>/dev/null ; if [ $? -eq 0 ]; then ps -o pid=,args= $i; fi; done
    ls -l /proc/1/fd | grep bpf-prog
    # Or:
    for i in $(ps ax -o pid= ); do ls -l /proc/$i/fd|grep "bpf-prog" &>/dev/null ; if [ $? -eq 0 ]; then ps -o pid=,args= $i; ls -l /proc/$i/fd | grep bpf-prog; fi; done
    # Traces open() syscall, showing which processes
    # are attempting to open which files:
    sudo /usr/share/bcc/tools/opensnoop

Mehedi Hasan's "Firewall Software For Protecting Your Linux System"
Eric Geier's "Little Known GUI Firewall Options for Linux"

IDSs and loggers and file-checkers

+/- List of Open Source IDS Tools
Daniel Berman's "6 Open Source SIEM Tools"

Honeypots and tar-pits

Vinsloev's "Cybersecurity 101 - What is a Honeypot?"
paralax / awesome-honeypots

Nix-Pro Wiki's "Packet journey through Linux kernel"

Application Control and Security

Maybe decide what is important to you.

Isolate applications from each other and the OS

Solutions from lightest to heaviest:
  • No isolation: userid gives every app access to all of your files, X gives apps access to each other's event-queues. Native packaging: deb, rpm, etc.

  • Sandbox created by someone other than app dev: AppArmor, Firejail.

  • Container (and permissions) created by app dev: Snap, Flatpak, Docker. All containers run on top of same, shared OS.

  • Micro-VM or unikernel for each app ? A severely stripped-down server image. If you're going to run a single process, no GUI, no SSH, single user, no command-line shell, then strip lots of stuff out of the Linux kernel-plus. Even run kernel and app in same address space.

  • VM for each app. OS is a "full" server distro such as Ubuntu server or a minimal distro such as Alpine.

  • Separate bare metal for each app. OS is a "full" server distro.

Not sure which is better: security set by app dev (e.g. in Snap), or by a third party (e.g. in AppArmor). App dev knows the app best, but OTOH a third party totally focused on security may do a better job.

Latest software

Solutions from fastest to slowest:
  • Container / image created by app dev: Snap, Flatpak, Docker, appimage.

  • Distro maintainer does native packaging: deb, rpm, etc.

  • LTS distro / stable repo.

  • VMs created using LTS software.

Low-level kernel stuff and building blocks


Lowest-level stuff

  • Namespaces:
    Wikipedia's "Linux namespaces"
    Mahmud Ridwan's "Separation Anxiety: A Tutorial for Isolating Your System with Linux Namespaces"
    Ed King's "Linux Namespaces"
    Mihail Kirov's "Digging into Linux namespaces - part 1 "

    Namespaces are a key feature used to implement isolation for container systems (Docker, flatpak, snap, LXC), applications and daemons (AppArmor, Firejail), and multi-process applications (some browsers).

    man namespaces
    man lsns
    lsns		# list namespaces in use by current user
    sudo lsns	# list namespaces in use by all users
    unshare -c -n APPNAME    # run APPNAME with no network access

    A program uses the clone() system call instead of fork(), to make a copy of itself running in a separate space. That can mean separate process trees (clone can't see parent process or any pre-existing processes), different views of the network connections, separate mount spaces (/etc/fstab's, I think), pseudo-root privileges, separate IPC spaces, more. There can be sockets set up to communicate between namespaces.

    In the CLI, you can use the "unshare" command to run a process in a separate namespace. The "ps" command has options to display namespace IDs for processes.

  • cgroups (control groups):

    Not a security mechanism. Used to control resource contention among groups of processes. Defines 13 resource categories ("controllers"), and lets you specify that process group A can use amount N of resource category R ?

    So, for example, normally if 2 applications start 5 processes each, those 10 processes all contend for resources on an equal footing. But suppose you want the 5 processes for application A to get higher priority for CPU than the 5 processes for application B ? Define each set of 5 processes as a separate cgroup.

    To run an app using limited amount of memory:
    cgcreate -g memory:GROUPNAME
    echo 500M >/sys/fs/cgroup/memory/GROUPNAME/memory.limit_in_bytes
    echo 5G >/sys/fs/cgroup/memory/GROUPNAME/memory.memsw.limit_in_bytes
    cgexec -g memory:GROUPNAME APPNAME
    but I'm not sure how the application will react if it tries to get more memory and is told "out of memory". It may crash or do something else unwanted.

    David Both's "Managing resources with cgroups in systemd"

  • Access Control Lists (ACLs):

    A way to set finer-grained permissions than the base UGO permissions.
    Kuldeep Sharma's "Secure Files/Directories using ACLs (Access Control Lists) in Linux"
    man acl
    man setfacl
    grep -i acl /boot/config*"	# see if enabled in kernel
    mount | column --table | grep acl	# any FSs mounted with ACL enabled ?

    Works on most Linux filesystems, but not vfat, exFAT, and some other non-Linux filesystems.

  • Capabilities:

    man page
    K3A's "Linux Capabilities in a nutshell"
    inaeem's "What's The Big Deal With Linux Capabilities?"
    Good info in Chapter 39 "Capabilities" of "The Linux Programming Interface" by Michael Kerrisk.

    "The goal of capabilities is to divide the power of superuser into pieces".

    There is a set of defined capabilities: audit-control, audit-write, network admin, network broadcast, etc.
    grep 'define CAP_' /usr/src/linux-headers-$(uname -r)/include/uapi/linux/capability.h | grep -v \( | grep -v LAST_CAP
    man capabilities
    A set of capabilities can be granted to a file, and then a process that execs that file gets those capabilities. Threads in a process can each have different capabilities. Capabilities can be inherited in various ways by daughter processes.

    Most applications probably aren't written to know or care about capabilities, and don't have any capabilities assigned to their executable file.
    getcap /bin/* /usr/bin/* /usr/bin/*
    And anything run by root user gets all capabilities.

Mid-level stuff

"cat /sys/kernel/security/lsm" to see what is present in your system.
  • iptables:

    You could assign an application to belong to a particular group, then make iptables rules about that group using "-m owner --gid-owner" qualifiers in iptables rules.

  • seccomp and seccomp-bpf (SECure COMPuting with filters):
    A Linux kernel security module that filters syscalls from a process.
    Calls to seccomp have to be written into the app's source code.

    The Linux Kernel's "Seccomp BPF (SECure COMPuting with filters)"
    Wikipedia's "seccomp"
    Gurkirat Singh's "Basics of Seccomp for Docker"

  • SELinux:
    A Linux kernel security module. More fine-grained than AppArmor and Firejail, which run at the application level, only at the interface between app and OS. Role-based permissions.

    Steven Vaughan-Nichols' "How to set up SELinux right, the first time"
    Alex Callejas' "A sysadmin's guide to SELinux"
    Gernot Klingler's "SELinux basics"
    Mike Calizo's "Secure your containers with SELinux"
    Gentoo Wiki's "SELinux"
    openSUSE's "SELinux"
    Wikipedia's "Security-Enhanced Linux"
    RHEL's "SELinux User's and Administrator's Guide"
    "Security-Enhanced Linux for mere mortals" (video)
    SELinux Project
    SELinux Project on GitHub
    Bug-report mailing list: selinux at
    Fedora's "Getting started with SELinux"
    Barrow's "Use SELinux Targeted Policy to Secure Your Hosts"
    Tyler Carrigan's "How to read and correct SELinux denial messages"
    CentOS's "SELinux Booleans"
    Good info in Chapter 24 "Enhancing Linux Security with SELinux" of "Linux Bible" by Christopher Negus.

    From Lubos Rendek's "How to disable/enable SELinux on Ubuntu 20.04 Focal Fossa Linux":
    Ubuntu offers AppArmor as an alternative to SELinux. While SELinux is available on Ubuntu, it is rather in an experimental stage and most likely will break your system if set to enforcing mode. In case you must use SELinux, make sure to disable AppArmor first. Also set SELinux first to permissive mode and check your logs for potential issues before you enable enforcing mode.

    From someone on reddit:
    It's hard to make a lot of sense from the tutorials because there's so much they cover, when most of the time you "only" need to get SELinux working with "just" Apache or "just" SMTP. Here's what I do:

    1. In the early stages of configuration, set SELinux to "permissive". This allows the same things as disabling does, except it will still generate errors in your log file.

    2. Install "setroubleshoot" and "setools", and reboot.

    3. One of the packages will install the "sealert" command, which will find errors in the log and help explain them to you, including suggestions on to how fix them. Just periodically, run "sealert -a /var/log/audit/audit.log" and follow the instructions.

    When you think you have all of the SELinux settings right (you're no longer getting errors in the log file), enable SELinux and reboot.

    I've heard that SELinux is better for servers rather than desktops. My desktop Fedora 34 KDE system does have SELinux enabled and enforcing, by default. But none of the user GUI apps are making use of SELinux; only the system apps and services are using it.

    Paraphrased from experienced sysadmins on reddit:
    "If you're using SELinux, go all-in, don't disable it or work around it. Any time something fails with no message, assume the problem is SELinux and look in the system journal for error messages and suggested remedies."

    # See if SELinux is installed and/or enabled:
    # Install it:
    sudo apt install selinux-utils selinux-basics policycoreutils setools setroubleshoot setroubleshoot-server
    sudo setenforce permissive
    sudo selinux-activate
    # Allow anything to run:
    sudo setenforce permissive
    grep CONFIG_SECURITY_SELINUX_DEVELOP /etc/selinux/config	# want "y"
    # Possible modes are: disabled permissive enforcing
    # In permissive mode, there can be a lot of logging going on
    # if lots of operations are (silently) failing security checks.
    # Note: changing mode can trigger (upon next reboot) a scan
    # of all files to relabel them (check security contexts).
    # Possible policy types are: targeted mls minimum
    # Edit /etc/selinux/config to set value in line SELINUXTYPE=whatever
    # If you set policy type to mls, first install package selinux-policy-mls
    # If you set policy type to minimum, first install package selinux-policy-minimum
    cat /etc/selinux/config
    man -k selinux
    man runcon
    man sandbox
    # runcon is a little dangerous, better to use sandbox
    secon -urt      # show security context of current process
    id              # show security context of current user
    sudo semanage user --list   # show all users/roles
    sudo semanage port --list   # show all TCP/IP port labels ?
    ls -Z                       # see labels on files
    sudo netstat -Ztulp         # see labels on listeners
    system-config-selinux		# show labels and path mappings and policy booleans
    sudo journalctl -t setroubleshoot --since=14:20
    # If you have auditing enabled:
    sudo aureport | grep AVC
    sudo ausearch -m avc
    # If you don't have auditing enabled:
    journalctl | grep sealert

    The label (AKA context) format is "user:role:type:level".

    SELinux is enabled / enforcing / targeted by default on RHEL and Fedora ?

    How to list all apps that have an SELinux policy defined ? Maybe "sudo semanage module -l" or "sudo semanage fcontext -l".

    From someone on
    You should almost never disable SELinux fully: when disabled, proper labels will not be applied to any changes to the filesystem, resulting in massive pain.

    If you're running into problems, set it to permissive mode instead, which keeps it active but not enforcing the policies.

    From someone on reddit:
    "tmpfs doesn't support things like SELinux fully due to limitations in tmpfs's xattr support."

    To create a policy set for an app:
    Red Hat's "Writing a custom SELinux policy"

    [I tried to write a simple policy for KeePassXC, and gave up. Would have been stuck at zero except for help from people on /r/selinux. Roadblock after roadblock, examples in docs are all about CLI commands instead of policy files, couldn't find any existing policies to copy, all kinds of mysterious things happening, then realized the app's code would have to be changed in concert with applying the policy.]

    1. Install "policycoreutils-devel".
    2. Install the app and its files.
    3. Test the application (unconfined).
    4. Use "sepolicy generate --init APPBINFILE" to generate a package of policy files that captures the current system state for that application.
    5. Run the setup script ("sudo ./") from that package to set the system state. This will set context on the app. But labels on any existing files will not be changed. To set app's label on a file, do "sudo semanage fcontext -a -t TYPENAME FILENAME" then "sudo restorecon -v FILENAME". (Seems to be a bug if "semanage FILENAME" uses a relative filename such as "../x") Also creates a manual page you can access via "man -l APPNAME_selinux.8". Have to reboot to make the "restorecon" take effect ? Do "sudo semanage fcontext --list | grep APPNAME" to see contexts labeled on files.
    6. Test the application (confined by new policies). To see that app is confined, "ps -efZ | grep APPNAME". To see that app's files are labeled, "ls -Z FILENAME".
    7. Check those policy files in to the SELinux project.

    Another way: "selinux-polgengui" ?

    A policy is tied to an app binary's filename, so there is a single policy per app. But you can let the user/admin pass values in to the policy (via semanage). So you can have variables such as "network allowed or not" set by the admin.

    Networking can be turned on/off, TCP/IP ports can be controlled, but there is no way to control the IP addresses or domains that can be accessed.
    When the SELinux policy has been loaded, all newly created files will be automatically labelled according to the specifications in the file context (.fc file).

    D-Bus access: better to control via polkit/policykit instead of SELinux.

    There seems to be no way (short of changing app's source code) to say "any time app creates a file anything.EXT anywhere, label it with role APPNAME_EXT_t". You CAN do this (using "filetrans_pattern") if you can confine those files to being created only in a fixed directory.

    Is there a way to apply a label to a shell script, and have it work at run time ? Is there a generic "backupapp_t" type ? I want app K's files to be accessible only to app K and to the backup scripts.

    In an app's C code, include selinux.h and then make calls to libselinux. For example, setfscreatecon() and then open(O_CREATE).

    My thoughts:
    +/- To my mind, all things that represent layers of defense (SELinux, AppArmor, Firejail, firewall, iptables, VPN config, OpenSnitch, etc) really are useful to the extent that you the owner/sysadmin can confirm that the policies are what you want. Otherwise, you're just trusting someone else's programming. I guess that's still valuable, in that it's unlikely that say Firefox and the Firejail profile confining it would both fail in the same way, letting some breach occur.

    But really, I want something with policies I can read and understand. And of the list above, only SELinux fails that test. I find SELinux's policy syntax and structure impossible to understand with a reasonable effort, and you have to look at file permissions and roles and hooks in the app etc. I was able to somewhat casually read AppArmor and Firejail profiles, iptables rules, ufw rules, etc. Not so with SELinux. It's complicated. I wanted to create an SELinux policy for an existing app; not going to happen.

    So, I'd say, if SELinux is installed in your system, leave it alone, leave it running. But you won't be able to understand what policies it's enforcing.

    Daniel Aleksandersen's "SELinux is unmanageable; just turn it off if it gets in your way"

  • Yama:

    A Linux kernel security module. Seems to be very narrowly focused on ptrace ?
    Michael Boelen's "Protect against ptrace of processes: kernel.yama.ptrace_scope"
    "sysctl kernel.yama.ptrace_scope" (3 == no ptracing)
    "sysctl kernel.yama"

  • Landlock:

    A Linux kernel security module. Coming in kernel 5.13.
    Landlock: unprivileged access control
    Mickael Salaun's "Landlock: unprivileged access control"

  • Lockdown:

    A set of Linux kernel features to optionally close off interfaces that allow root to modify the kernel.
    Matthew Garrett's "Linux kernel lockdown, integrity, and confidentiality"
    Arch Wiki's "Kernel lockdown mode"

  • SMACK:

    A Linux kernel security module.
    Wikipedia's "Smack"
    The Smack Project - Home


    A Linux kernel security module.
    Wikipedia's "Tomoyo Linux"
    TOMOYO Linux
    eLinux's "TomoyoLinux"

  • IMA (Integrity Measurement Architecture):

    Huzaifa Sidhpurwala's "How to use the Linux kernel's Integrity Measurement Architecture"

  • Bubblewrap:

    "man bwrap"
    ArchWiki's "Bubblewrap"
    valoq / bwscripts

Kernel Modules / Drivers:

# all available kernel modules:
find /lib/modules/$(uname -r)/kernel -name '*.ko' -print | sort | less
find /lib/modules/$(uname -r)/kernel -name '*.ko.zst' -print | sort | less

lsmod | sort | less   # see loaded modules

modinfo MODNAME       # see info about module, incl params when loaded
# If module is dynamically loaded, filename will be /lib/modules/*/*.ko
# If module is compiled-in, filename will be "(builtin)".

ls /etc/modprobe.d    # configs for loadable mods, incl blacklisting

To disable a compiled-in driver, blacklist its init() function. Add something like "initcall_blacklist=DRIVERNAME_init" to kernel command line. You may have to look at source code to find the exact name of the init() function.


Kernel Parameters / Kernel Command Line / System Parameters:

cat /proc/cmdline       # see kernel launch command line
sudo dmesg | grep 'Kernel command line'     # ditto

sudo sysctl -a | less   # see kernel parameters
zcat /proc/config.gz    # see kernel parameters

modinfo amdgpu          # see parameters supported by amdgpu module
# These parameters can be passed in through the kernel boot command line.

less /boot/config-$(uname -r)   # see current kernel configuration

less /etc/sysctl.conf   # see system variables
getconf | less

man kernel-command-line

Jason Andress's "Tales from the Kernel Parameter Side"'s "The kernel's command-line parameters"
EndeavourOS's "ACPI Kernel Parameters and how to choose them"
Vivek Gite's "How to view Linux kernel parameters for currently booted system"

Many ways to add/change a parameter:
  • Change in /proc.
    Not persistent; current session only.
    E.g. "sudo echo 0 >/proc/sys/net/ipv4/ip_forward"

  • Change using sysctl command.
    Not persistent; current session only.
    E.g. "sudo sysctl -w net.ipv4.ip_forward=0" then "sudo sysctl -p"

  • Change in /etc/sysctl.conf file, or in added files under /etc/sysctl.d/.
    E.g. "sudo echo "net.ipv4.ip_forward=0" >>/etc/sysctl.d/net.conf"

  • Change in bootloader configuration file.
    "Change GRUB Configuration" section

  • Change in bootloader menu just before booting.
    Not persistent; current session only.

Gabriel Canepa's "How to Change Kernel Runtime Parameters in a Persistent and Non-Persistent Way"

Service and app-level stuff

  • Firejail:
    An application that restricts the environments of other apps, running them with access only to certain directories, or to fake copies of system directories, or no network access. Application-based permissions.

    From Firejail Security Sandbox:
    Firejail is a SUID program that reduces the risk of security breaches by restricting the running environment of untrusted applications using Linux namespaces and seccomp-bpf. It allows a process and all its descendants to have their own private view of the globally shared kernel resources, such as the network stack, process table, mount table.

    Firejail Security Sandbox
    Easy Linux tips project's "Run your web browser (and other apps) in a secure sandbox"
    Jesse Smith's "The Firejail security sandbox"
    netblue30 / firejail
    netblue30 / firetools
    "firejail --version" (shows more than just version number)

    Firejail works on native binaries and on appimages (with --appimage option), but not on Snaps or Flatpaks or Docker containers.

    Does Firejail work on browsers and terminals launched from other apps, such as VS Code ?

    "sudo apt install firejail firejail-profiles firetools".
    Profiles stored in /etc/firejail.

    Poked around a bit, quickest way to see the restrictions is to run "mount | column --table" in CLI before and after running "firejail bash". Also "firejail --audit APPNAME".

    To run an app while denying network access:
    firejail --net=none APPNAME
    This is equivalent to editing the ~/.config/firejail/APPNAME.local file to add "net none".

    To run an app using limited amount of memory:
    firejail --rlimit-as=NUMBYTES APPNAME

    Local system edits could be done to either ~/.config/firejail/APPNAME.local or /etc/firejail/APPNAME.local.

    Easy way to make any of your big apps run under Firejail: create symlinks for them that link to firejail:
    sudo ln -s /usr/bin/firejail /usr/local/bin/firefox
    which -a firefox        # check PATH
    # then if run "firefox", from either CLI or icon, will run "firejail firefox"

    Easy way to make ALL apps known to Firejail run under Firejail:
    sudo firecfg
    which -a firefox        # check PATH
    # Then if run "firefox", from either CLI or icon, will run "firejail firefox"
    # If you install another application, do same again:
    sudo firecfg
    firecfg --list          # list all links
    sudo firecfg --clean    # remove all links
    # On Kubuntu 20.10, Firejail version
    # I found that I had to remove Dolphin's
    # link to fix problems with running sudo in shell scripts:
    sudo rm /usr/local/bin/dolphin
    # How to put /opt/thunderbird/thunderbird-bin inside Firejail ?
    # Firefox wouldn't launch.  Tried various directives in
    # firefox-common.local to fix it, no luck.  Removed it from Firejail.
    # Liferea wasn't able to send links to Firefox properly;
    # snap of KeePassXC was able to.
    # VS Code launched, then it didn't.
    # Gave up on Firejail on Kubuntu 20.10.

    # On Fedora 34 KDE using X, Firejail
    # Tried to run KeePassXC 2.6.4 under Firejail.
    # Clicking on links, and Ctrl+Shift+U to open link, didn't work.
    # In debug mode, get message:
    # "Unable to detect a web browser to launch 'http...'"
    # Bug reports:
    # you can apply a profile for one app to another app:
    firejail --profile=keepassxc ls ~/.mozilla
    With help from someone, got some basic sanity of Firejail-KeePassXC working. Still fails if browser has to be launched, but if browser is running already, clicking on a link works. Had to make file /etc/firejail/keepassxc.local:
    # keepassxc.local
    # If you click on an URL in KeePassXC, and default browser is Firefox, FF stub
    # gets launched inside the KP firejail, so need this to counteract what is
    # done in
    noblacklist ${HOME}/.cache/mozilla
    noblacklist ${HOME}/.mozilla
    # That works if FF is running before you click on an URL in KeePassXC.
    # If FF is not running before you click on an URL, a full copy of FF tries
    # to launch inside the KP firejail, and crashes.
    ignore private-bin
    ignore net none
    protocol unix,inet,inet6,netlink
    private-etc ca-certificates,crypto-policies,host.conf,hostname,hosts,nsswitch.conf,pki,protocols,resolv.conf,rpc,services,ssl
    Similar does NOT work for Brave or ungoogled-chromium browsers. Only FF works.

    General problem with launching stuff / opening links from inside Firejail, it seems:

    You could use Firetools or Firejail Configuration Wizard apps in the GUI. But building a security profile doesn't seem to be persistent, and the Firetools monitor shows a much-too-high number for memory usage. And the UI is really annoying.

    When trying to debug a Firejail profile, launch the app in CLI ("firejail APPNAME"), not via an icon. Apps often put out error messages on stderr. Also, do "sudo ps -ax | grep firejail" to make sure an app isn't hanging; reboot if there is one.

    Is there a way to see what attempted operations have been prevented by an app's profile ? Messages in system journal or something ?

    Firejail project home: netblue30 / firejail

    Interesting debate: Firejail worsen security? #3046

  • green check-mark  AppArmor:
    Very similar to Firejail, but implemented as a Linux kernel security module. Application-based permissions. Generally applied to services/daemons, and runs in the background without the user having to know anything about it.

    Do "sudo apparmor_status" to see info.
    To install more: "sudo apt install apparmor-profiles apparmor-profiles-extra apparmor-utils apparmor-easyprof apparmor-notify"
    Maybe add your user to group "adm" to get notifications ? "adduser USERNAME adm"
    "man -k apparmor"

    Wikipedia's "AppArmor"
    openSUSE's "Confining privileges with AppArmor"

    Making profiles:
    Ubuntu Tutorials' "How to create an AppArmor Profile"
    Uzair Shamim's "The Comprehensive Guide To AppArmor: Part 1"
    The Debian Administrator's Handbook's "14.4. Introduction to AppArmor"

    Chris Siebenmann's "On Ubuntu, AppArmor is quite persistent and likes to reappear on you"

    In Mint, Apparmor (user-space parser utility) was installed by default.
    I installed Apparmor-utils through Software Manager.
    Profiles are stored in /etc/apparmor.d directory.
    You could turn on the profile for Firefox by doing "sudo aa-enforce /etc/apparmor.d/usr.bin.firefox".
    To turn it off, do "sudo aa-disable /etc/apparmor.d/usr.bin.firefox".
    If you do a disable when enforce is not on, you'll see a "Profile doesn't exist" error.
    To see the list of active profiles, do "cat /sys/kernel/security/apparmor/profiles".
    To see AppArmor activity, do "grep apparmor /var/log/kern.log".

    When trying to debug an AppArmor profile, launch the app in CLI, not via an icon. Apps often put out error messages on stderr. Also, do "sudo ps -ax | grep APPNAME" to make sure an app isn't hanging; reboot if it is.

    Firefox with AppArmor:
    Already had FireFox working in Firejail, so all of the following is with FF running in Firejail.

    Started enforcing AppArmor for Firefox, launched Firefox in Firejail, it showed some "welcome to Mint - file access failed" page, and the kernel log shows a dozen or more AppArmor "denied" messages.

    Quit Firefox, disabled AppArmor for Firefox, launched Firefox, and my Firefox user profile is gone ! Bookmarks, settings, add-ons, everything gone !

    Fortunately, I was able to find it all under a directory in "~/.mozilla/firefox", and was able to restore it by editing "~/.mozilla/firefox/profiles.ini" to point at the old profile instead of the new one. Whew ! Do a backup of that stuff before trying again.

    Looking at "denied" messages in /var/log/kern.log, it looks like access to "/run/firejail/mnt/" is denied, maybe also access to "home/.ecryptfs/USERNAME/...". Edited "/etc/apparmor.d/usr.bin.firefox". Above "# so browsing directories works", I added lines "/run/firejail/mnt/** r," and "/home/.ecryptfs/** rw,".

    Still got "bookmarks and history system will not be functional because one of Firefox's files is in use by another application. Security software can cause this problem." error message.

    Tried AppArmor on, Firejail off, and FF works ! So the problem is somewhere in the interaction of AppArmor and Firejail. Did "sudo xed /etc/apparmor.d/firejail-default /etc/apparmor.d/usr.bin.firefox ~/.config/firejail/firefox.profile". Couldn't fix the problem. Tried adding lines "network unix stream, network netlink stream," and "/run/firejail/mnt/** r, /home/.ecryptfs/** rw," to "/etc/apparmor.d/usr.bin.firefox", didn't help.

    If you caused a bunch of FF crashes while debugging, look in "~/.mozilla/firefox/'Crash Reports'/pending" and delete them.

    Dedoimedo's "Firefox & AppArmor hardening - Custom rules"

    KeePassXC with AppArmor:
    Mint 19 has no AppArmor profile for KeePassXC.

    Made a profile the stupid way, trial-and-error, not using the profiling tools. Started with no restrictions.
    "sudo aa-enforce /etc/apparmor.d/usr.bin.keepassxc"
    "sudo aa-disable /etc/apparmor.d/usr.bin.keepassxc"
    "sudo apparmor_parser -r /etc/apparmor.d/usr.bin.keepassxc"
    Got it to work, despite showing "qt5ct: D-Bus global menu: no" error (same error when AppArmor is disabled).
    Tried to turn off networking, got "Could not connect to any X display" error. Adding "network unix stream" fixed that. Very unfortunate that I had to do that; my main goal for this profile was to turn off networking.
    Took a lot of fiddling to get the directory-tree permissions okay; I'm sure they're still too generous.
    Ended up with this.

  • Pledge:
    An application that restricts the environments of other apps, similar to Firejail. For apps launched from CLI.
    Jesse Smith's "Pledge on Linux"
    Justine's "Porting OpenBSD pledge() to Linux"

  • green check-mark  OpenSnitch:
    Runs on top of iptables; nftables coming later. Also uses eBPF.
    Handles TCP, UDP, and UDPLITE traffic.
    Only handles outbound connections (inbound may be under development).
    Unclear how it interacts with VPNs and firewalls that write iptables rules; dev says there should be no problems.
    Couldn't get it to run on a system that was not using systemd.

    Can block on the basis of applications, as well as domains and ports.
    Can block traffic from apps run by systemd services.
    Can it block traffic from init-scripts, cron jobs ?
    Can it block Bluetooth traffic ?
    Doesn't show traffic coming out of VPN client.
    Only blocks domain, not full URL (e.g. not "").
    Seems to be no difference between using X and using Wayland.

    "sudo systemctl status opensnitch --full --lines 1000"

    May have to install "python-notify2" to get UI to work. Try running opensnitch-ui from CLI, look at error messages.

    There is a way to save rules to CSV file, but no way to import that file back in later (version 1.5.0). Instead, save/restore /etc/opensnitchd/.

    To restrict an application to ports 1000 and above, use regex "^([1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9])$".

    nixCraft's "OpenSnitch: The Little Snitch application like firewall tool for Linux"
    Sk's "Taking Linux Security To The Next Level With OpenSnitch Firewall"
    Step 3 in TokyoNeon's "Using Ubuntu as Your Primary OS, Part 4 (Auditing, Antivirus & Monitoring)"
    Do Son's "opensnitch: GNU/Linux port of the Little Snitch application firewall"
    Linux Uprising's "OpenSnitch Application Firewall 1.4.0"
    Linux Uprising's "OpenSnitch 1.3.0"
    Jesse Smith's "OpenSnitch - an application firewall for Linux"
    evilsocket / opensnitch

    My strategy on rules:
    • Allow all apps to 53 (DNS).

    • Deny all apps to 1900 (PnP). But media server wants to use this port, and there's no way to say "deny to all apps except app A".

    • Deny all apps to location services:,,, (can't be done:)

    • Allow torrenting apps and media server apps to access any port over 999 (they use random high ports).

    • If there are some apps (e.g. password manager) that never will try to access the network, you'll never get a pop-up asking you to create a rule about them. So go ahead and add a deny-everything rule anyway.

    • Some DE parts/apps use "curl" to do accesses, so you'll see curls that you didn't do manually. No good way to distinguish them from curl's you do manually on CLI.

    • Some apps (feed reader) use "wget" to do accesses, so you'll see wgets that you didn't do manually. No good way to distinguish them from wget's you do manually on CLI.

    • Some apps (browsers, more) use WebKit sub-processes. No way to control those by originating application.

    • Some KDE apps use kioslave sub-processes. No way to control those by originating application.

    • Some KDE apps (Akregator) sometimes cause a "kernel connection" sub-process ? No way to control those by originating application.

    • When you move from one distro to another, some apps will be installed in different places, maybe even with different filenames. So you end up duplicating their rules. Can't put a regex in an application name in a rule.

    • Apparently, appimages are tricky, their location is in /tmp and changes each time they run ? You have to make a rule for a path something like /tmp/\.mount_[a-zA-Z0-9]+/your/path/app.appimage

    • Where possible, go into apps and stop them from generating traffic you want to deny. In Firefox, set browser.topsites.contile.enabled = false, dom.push.connection.enabled = false, dom.push.enabled = false. Then you can get rid of the corresponding deny rules. Also maybe turn off Network Manager connectivity-checking. Then you can remove the corresponding deny-rules.

    • After the rules seem to be working, look in the Events tab and maybe adjust the rules.

  • Douane:

    Douane on GitLab

    Tuxdiary's "Douane: easy firewall with app rules"
    Dedoimedo's "Linux per-application firewalls - Doable? Douane"
    Project-insanity's "Application firewall Douane for ArchLinux"

  • eBPFSnitch:

    harporoeder / ebpfsnitch
    Filtering inbound connections not supported as of 1/2022, according to README.
    For any distro except Arch, must be compiled from source, as of 1/2022.

  • picosnitch:

    Does monitoring/logging/notification, but not blocking.

  • Portmaster:

    Raphael's "Portmaster 1.0"
    Martin Brinkmann's "First look at Portmaster"
    Has ad, malware, and tracker blocking.
    Has a for-pay super-VPN: SPN, €10/month.
    Uses iptables.
    Couldn't get it to run on a system that was not using systemd.

  • ip rule/route:

    Prevent traffic to/from an IP address or subnet.
    More efficient than an iptables rule ?

    See "Linux Network Interfaces" section.

  • Trickle:

    ArchWiki's "Trickle"
    Reduce bandwidth available to a single process.

  • Docker to isolate a single process ?

    "docker run --rm -it -v $PWD/untrustedprogram:/untrustedprogram:ro ubuntu:latest" ?

  • ulimit

    To run an app using limited amount of memory:
    ulimit -Sv NUMKBYTES

  • cpulimit:

    Gregory Bartholomew article
    Limit CPU available to a single process.

  • corectl:

    Automatically configure your system when a program is launched.

Chris Siebenmann's "The likely long-term result of good on-host (host-based) firewalls"

My evaluation

The mainstream solutions (at least, in Mint) seem to be Firejail and AppArmor.

  • Firejail better because:
    • Can have different icons that launch an app with/without Firejail.
    • Can have private copies of /dev, /bin, /tmp, /etc.
    • Easy to say nodvd, noshell, noroot.
    • In Mint, there are far more Firejail profiles than AppArmor profiles.

  • AppArmor better because:
    • No way to evade controls when you launch an app.
    • Lots of fine-grained controls on D-Bus.
    • Can set detailed rwxmk permissions on directory trees and files; Firejail just has whitelist/blacklist.
    • Has some kind of controls on "signals".

  • Neither AppArmor nor Firejail supports restricting network access to just X system, or just localhost, or just LAN addresses.

  • Trying to use both AppArmor and Firejail on same app usually fails.

  • In Mint, by default, AppArmor is controlling several daemons, such as dhcp, cups, mysql-akonadi, Clam updater, ippusbxd (USB printer).

  • I think I would try to get my key applications running in Firejail. Leave AppArmor enforcing on the daemons.

Opinion: firewalls / app control / security is a mess

Firejail, AppArmor, SELinux, Yama, iptables, ip6tables, nftables, bpf, ufw, gufw, firewalld, netfilter, VPN, IDS, IPS, etc. Why can't we have one integrated solution, with a body of rules that can do filesystem and network access and syscall access and service and app and login control, and take user ID, app ID, MAC address, IP address, IP port, etc as input to the rules ?

  • I'd like to control Firefox now. I go to the Security GUI, select Firefox, and I see everything about it: what files/dirs it can access, what syscalls it can do, what devices, what IP ports, domain whitelists and blacklists, what users/groups can access it, everything. All in one place. I don't care if separate kernel modules do the networking and the filesystem control, and some module inside Firefox does the domain whitelist/blacklist.

  • Same for any other app or service or module. I go to the Security GUI and choose my password manager app. In one place, I can control everything about it: filesystem access, network access, syscalls, etc.

  • I don't want my system to do anything with IPv6. I go to the Security GUI and choose IPv6. In one place, I can control everything about it: turn it off for everything, turn off incoming, whatever. Later, maybe I decide only Firefox can do IPv6. I can check a box to allow that.

  • "Networking" should have zones: can/can't access internet, can/can't access router, can/can't access other devices on LAN, maybe also services listening on localhost. And internally X11 does networking, so that has to be allowed.

  • I don't want user "skype" (which owns Skype app and the cron job that updates it) to be able to contact any domains except Microsoft's Skype domain. I go to the Security GUI and choose user "skype" and set the appropriate things.

I think today Firejail and AppArmor already mix some of this. You can set filesystem, syscall and network permissions in a Firejail profile or an AppArmor profile, I think. But Firejail and AppArmor settings are hard to share across many apps, and iptables rules know nothing about applications/processes. Iptables has a module that allows rules based on connection state, but I don't think Firejail and AppArmor have anything like that.

Interesting: make a noise any time a tracker domain is accessed:
Bert Hubert's "Tracker Beeper" (Google only, *nix only)

System Hardware Monitoring and Control

Periodically check the health of your drives. Record the stats.
Wikipedia's "ACPI"'s "ACPI Support"
mjg59's "Why ACPI?"
UEFI's "Links to ACPI-related Documents"

Software Resource Monitoring

Network Monitoring

This section is for tools used by a person. For tools that generally run unattended, see the Network Control section.

Some terms:

Traffic monitoring and analysis

  • netstat:

    To see what incoming ports are open and/or have listeners on them, do "sudo netstat -tulp".

    To see what connections have been established and by what app, do "sudo netstat -tp".

    Mehedi Hasan's "Linux Netstat Command Tutorial for SysAdmins"

  • ss:

    To see what connections have been established, do "ss -tun state connected".

  • lsof:

    To see established connections, do "sudo lsof -i" or "lsof -i TCP".

  • iptraf-ng:

    Ran "sudo iptraf-ng". If you want names instead of numbers, go into "Configure" and turn on "Reverse DNS lookups" and "TCP/UDP Service names". Exit out of Configuration and then go to "IP traffic monitor".
    Shows both UDP and TCP.

  • iftop:

    Ran "sudo iftop -P". Type "h" to get into and out of help screen.
    It does show cumulative totals; you may have to press "T".
    But it just shows IP addresses and port numbers; no app or service names.

  • Nethogs:

    Ran "sudo nethogs".
    But it seems to show only currently active processes, not a historical/cumulative log.
    Aha ! "sudo nethogs -v 3" will show cumulative, so apps don't disappear from the list after they terminate.

    Tried to install hogwatch, but got a lot of "error: invalid command 'bdist_wheel'" problems.

  • ntopng:

    But it won't start up, says address or port 3000 is busy. Turned off VPN, maybe iptables is stopping it, gave up.

  • rpcinfo:

    Not sure if this is obsolete.
    Only applies if "portmapper" is being run ?
    Portmap is required by NFS ?
    "sudo rpcinfo -p localhost"

  • conntrack-tools:

    conntrack-tools: Netfilter's connection tracking userspace tools
    conntrack (8) - Linux Man Pages
    To install: "sudo apt install conntrack".

  • dnspeep:

    Julia Evans' "A tool to spy on your DNS queries: dnspeep"

  • Justniffer:

    Thought about installing Justniffer, but it looks old, decided against it. If I'm going to learn some big complicated tool, it's going to be Wireshark.

  • Wireshark:

    Tried running Wireshark from GUI Start button, but none of the 4 "capture filters" it shows me seem appropriate.
    Ran "sudo wireshark" from CLI, and it gave a warning but then showed me interfaces I expected, including my Ethernet adapter. Chose that, and it started live monitoring of packets.

    If you see a lot of UDP traffic labeled as "QUIC", Wireshark probably is guessing wrong, and: "If you don't want the QUIC tag, simply go to the "Analyze" menu and select "Enabled Protocols" from the list. Find the entry for QUIC and uncheck the box."

    Did "sudo usermod -a -G wireshark MYUSERNAME" so I can run Wireshark without sudo.

    In Wireshark, do "Capture / Options" and turn off "promiscuous mode" to see traffic just for your computer, not all traffic on the LAN.

    Chris Hoffman's "How to Use Wireshark to Capture, Filter and Inspect Packets"
    OTW's "Network Forensics: Wireshark Basics, Part 2"
    Ceos3c's "Wireshark Tutorial Series 1 - Introduction, lab setup and GUI overview"
    FromDev's "30+ Best Free Wireshark Tutorials PDF & eBooks To Learn"
    Brad Duncan's "Using Wireshark: Identifying Hosts and Users"
    elitest's "Decrypting TLS Browser Traffic With Wireshark - The Easy Way!"

    There's also a CLI version/part of Wireshark: tshark

    PA Toolkit (Pentester Academy Wireshark Toolkit)

  • Nikto:

    Web server testing.

  • arpwatch:

    Tool for seeing ARP traffic, alerting if a new MAC-to-IP address mapping appears or an existing one changes.

    Wikipedia's "arpwatch"

  • gupnp-tools:

    See uPNP traffic.
    "sudo apt install gupnp-tools"

    Run "GUPNP Universal Control Point" application (on CLI: gupnp-universal-cp) to display traffic.
    No man page, but see "gupnp-universal-cp --help".
    Works with VPN on or off: I see uPNP traffic from our smart TV.

    Another application: "GUPnP AV Control Point" application (on CLI: gupnp-av-cp) to get a remote control UI.
    I can't get it to control our smart TV, but if I use the TV's remote control to change the volume, the app's volume slider moves to reflect the change.

Chris Siebenmann's "Internet routing can now vary based on things you wouldn't expect"
Mehedi Hasan's "Linux Monitoring Tools For SysAdmin"
Hayden James' "Linux Networking commands and scripts"
Martin Bruchanov's "Linux Network Administration"

Monitor the traffic in/out of your LAN. Best ways probably are custom software in your router, and a Pi-hole doing DNS filtering. From Security in Five Podcast - Episode 746, investigation of traffic volume exceeding data cap found that iCloud was uploading/downloading the entire collection any time one thing was added, and after that was fixed almost 50% of all traffic was due to blockable scripts (ads, trackers).

Endpoint monitoring

I want a monitoring app on my Linux system that tells me how much free storage/disk each device on the LAN (Windows laptops, Android phones and tablets, printer) has, last time it was updated, is it on the network right now. That's about it. I don't really care about network traffic monitoring.

It looks like all the managers work by using DNS to name and access devices. You'll have to set static IP assignments in the router, and put names/numbers in /etc/hosts on manager machine, then "sudo systemctl restart systemd-resolved", then "ping NAME".

Some people are telling me that there is a market separation between "network monitoring (SNMP)" products [LibreNMS, Icinga, more] and "mobile device management (MDM)" products [Quest Kace, JAMF, Spiceworks, Intune, more], and you will not find one product which can monitor both servers and smartphones, for example.

System Types

  • Custom agent on each client: install a custom "agent" app or service on each client device, get lots of detailed information and control.

  • SNMP agent on each client: install or enable an SNMP agent app or service on each client device, get varying amount of information and control.

  • Agentless: manager does network access (ping, HTTP, whatever) to each client to see if it is alive and seems to be functioning as intended. Little information, probably no remote control.

Agent Types

  • Passive: agent just collects data and responds to requests/orders from manager. So all clients have to have fixed known IP addresses ?

  • Trap: when some trigger happens (e.g. free disk space goes below 10%), agent sends an event to manager. So only manager has to have fixed known IP address ?

  • Both

Network Managers

  • EventSentry Light:

    Limited to 5 devices ? Maybe limited only for updating/control ?
    Server runs on ???
    Agents available for ???

  • Zabbix:

    Server runs on Linux.
    Agents available for Linux, Mac, Windows.
    There is an Android app "Unofficial Zabbix Agent" by dentier.
    "docker pull zabbix/zabbix-server-mysql" and "docker run -p 8080:8080 zabbix/zabbix-server-mysql"
    "docker pull zabbix/zabbix-web-nginx-mysql" and "docker run -p 8080:8080 zabbix/zabbix-web-nginx-mysql"

  • LibreNMS:

    Server runs on Linux and Windows/Docker.
    No agents, devices must have static IP address and SNMP.
    LibreNMS was forked from Observium before Observium became a commercial product.
    Installing LibreNMS

    There is a Docker image, "docker pull librenms/librenms" and "docker run -p 8080:8080 librenms/librenms", but it expects you to have a running MySQL database first.

    Tried native install:
    # See
    # I followed the "sudo -s" / Ubuntu / Nginx path.
    # but starting mariadb and OpenIPMI services failed.
    # Removed everything:
    # Do NOT remove mysql-server and mariadb-server !  desktop went with them !
    sudo rm -r /opt/librenms
    sudo deluser librenms
    sudo delgroup librenms
    # Ended up in a state where neither MySQL nor mariadb will re-install.

  • Icinga 2:

    Server runs on Linux.
    No agents, devices must have static IP address and SNMP.
    Can use Nagios plug-ins.
    There is an Android app "Probe for OMD and Nagios" by Marco Ribero.
    "docker pull jordan/icinga2" and "docker run -p 8080:8080 jordan/icinga2"
    "sudo apt install icinga2"

  • Observium Community:

    Server runs on Linux, more ?
    Agents available for xxx
    Tagged as "simple to use" in reviews.
    It seems that a client device MUST have an agent running on it (responding to SNMP queries) before you can define the device in the manager application; there's no way to define the device and then just get traps from it (at least in CE).

    Tried Docker image (FAILED):
    docker pull uberchuckie/observium
    # See
    # paths have to be full paths !
    #docker run -d -v /your-config-location:~/projects/observium/config -e TZ="Madrid" -v /path-to-logs:~/projects/observium/logs -v /path-to-rrds:~/projects/observium/rrd -p 8668:8668 uberchuckie/observium
    docker run -d -v /your-config-location:/home/user1/projects/observium/config -e TZ="Madrid" -v /path-to-logs:/home/user1/projects/observium/logs -v /path-to-rrds:/home/user1/projects/observium/rrd -p 8668:8668 uberchuckie/observium
    docker container list
    # Browse to http://localhost:8668
    # Log in as observium / observium
    # Fail: it just ran and ran, never created subdirs,
    # didn't respond to browser.
    # Later, the image owner said there are a whole
    # lot of undocumented reqts, such as run inside unRAID,
    # assumes that there is a "nobody" user with user id 99 and
    # group id 100.  I didn't retry.
    # When done:
    docker stop CONTAINERID
    docker images
    docker rmi IMAGEID
    # if it says there are stopped containers:
    docker rm CONTAINERID

    Tried native install:
    # See
    chmod +x
    sudo ./
    # choose Community Edition
    # Said "no" to installing snapd and agent.
    # set MySQL password
    # set Observium admin acct name and password
    # Observium CE 20.9.10731
    sudo systemctl restart apache2
    # Browse to http://localhost:8668 or
    # FAIL
    # Browse to http://localhost
    # Log in; works okay.
    # Decided to remove it.
    sudo apt remove apache2 php7.4-mysql mysql-server mysql-client rrdtool
    sudo rm -fr /opt/observium*
    sudo rm /etc/cron.d/observium
    sudo deluser observium
    sudo delgroup observium

  • MeshCentral:

    Seems very beta 11/2020.
    Server runs on Linux or Windows.
    Agents available for Linux, Windows

  • Xymon Monitor:

    The Xymon Monitor
    Server runs on Linux.
    Agents available for Linux, Windows.
    Need to have web server (e.g. Apache) installed, and C compiler and make utilities.
    Seems to expect a dedicated server, where you log in as user "xymon" and run a daemon.
    Latest update 2019-09.

  • Checkmk:

    Server runs on Linux.
    Has Nagios inside.

  • uMon:


  • Linux SNMP CLI utilities:

    There is no constantly-running manager command ?

    There IS a trap-handler daemon, which will receive messages from clients and maybe send email to notify. First, set up the Linux agent software (see "agents" section). Then:
    sudo systemctl start snmptrapd
    # Snmptrapd service says:
    #		Warning: no access control information configured.
    #		This receiver will *NOT* accept any incoming notifications.
    man snmptrapd
    man snmptrapd.conf
    sudo edit /etc/snmp/snmptrapd.conf
    # un-comment line "authCommunity log,execute,net public"
    sudo systemctl restart snmptrapd
    sudo systemctl status snmptrapd --full --lines 1000
    sudo netstat -tulpn
    sudo journalctl --unit='snmp*' --pager-end

  • Simple Android manager-type apps, mainly for testing:

    • "Fing - Network Tools" by Fing Limited.

      Under a machine's "Network Details" section, it will show SNMP machine name, contact, location. But in a port scan, it will not show machine's port 161 as open, I think because SNMP is using UDP.

    • "SNMP MIB Browser" by Zoho Corporation.

      When installed, just has one MIB "RFC1213-MIB", stored on phone as three files in "Internal shared storage / mibs" folder. There is a similar file "/var/lib/snmp/mibs/ietf/RFC1213-MIB" on my Linux system. Copied all MIB files from remote device (e.g. /var/lib/snmp/mibs/ from my Linux laptop) to phone, NOT replacing the RFC1213-MIB that was there already.

      When you add a host to the "Host List", the circle to the left of it will turn green if the SNMP connection to it is successful.

      When polling for an ObjectId value, you can put in an ObjectId such as ".", or a name if you've loaded the MIB where that name is defined. Some names and their MIBs are "sysDescr" (SNMPv2-MIB), "sysLocation.0" (SNMPv2-MIB). "hrSystemProcesses.0" (HOST-RESOURCES-MIB). If you put in a name and start polling and get no response at all, probably you have not loaded the MIB needed to translate that name.

      After you've successfully connected to the client system, you can go into "SNMP MIB Browser" and you will find that all the fields have been filled in with the values obtained from the client.

DNSstuff's "Best Linux Network Monitoring Tools for 2020"

All of the above systems seem to be huge overkill, and few of them support Android phones.

SNMP Agents

  • Linux SNMP CLI utilities:

    To get SNMP agent working locally:
    sudo apt install snmp
    man snmpget
    man snmpcmd
    man snmpstatus
    man snmptrap
    man -k snmp
    sudo apt install snmp-mibs-downloader
    sudo sed -i 's/mibs :/# mibs :/g' /etc/snmp/snmp.conf	
    sudo apt install snmptrapd	# can log incoming SNMP notifications to syslog etc
    sudo systemctl status snmpd --full --lines 1000
    sudo systemctl status snmptrapd --full --lines 1000
    sudo systemctl enable snmptrapd
    sudo systemctl start snmptrapd
    sudo netstat -tulpn
    # man snmpd.conf
    # sudo edit /etc/snmp/snmpd.conf to add:
    rocommunity  public default
    includeAllDisks 10%		# or e.g. "disk /home %10"
    # Note: default frequency for disk-checking is every 10 mins ?
    # But I don't see it logging anything, ever.
    # Then:
    sudo systemctl restart snmpd
    sudo systemctl status snmpd --full --lines 1000
    snmpwalk -c public -v1 localhost | less
    # notice that lines start with various "DISMAN-EVENT-MIB",
    # "SNMPv2-MIB", "IF-MIB", "SNMPv2-SMI", "IP-MIB",
    # "HOST-RESOURCES-MIB", more.
    snmpdf -v 2c -CH -c public localhost
    snmpps -v 2c -c public localhost | less
    watch --interval 5 snmpstatus -v 2c -c public localhost
    # every 5 seconds show Total RAM free:
    watch --interval 5 snmpget -v 2c -c public localhost .
    snmpdelta -v 2c -Cp 5 -c public localhost .
    # notice that lines start with "UCD-SNMP-MIB"
    To make SNMP agent accessible from network:
    # edit /etc/snmp/snmpd.conf to comment out
    # "agentAddress  udp:" line and add:
    agentAddress udp:161
    # or just comment out all the agentAddress lines.
    # add lines:    NO !!!
    createUser suser1 MD5 SOMETMPPASSWORD DES
    rouser suser1 priv
    # A different way to do it:    NO !!!
    sudo apt install libsnmp-dev
    net-snmp-create-v3-user --help
    sudo systemctl restart snmpd
    sudo systemctl status snmpd --full --lines 1000
    # Run gufw and add rules to allow IN/OUT on ports 161 and 162
    # from/to anywhere, with UDP, with IPv4.
    # get your LAN IP address (call it THEIPADDRESS):
    ip addr | grep 192.
    snmpdf -v 2c -CH -c public localhost
    snmpdf -v 2c -CH -c public THEIPADDRESS
    # should get machine's "name", which is output of "uname -a"
    # Go to manager app, such as Android apps in previous section,
    # and try to query values from this system.
    # Got stuck at this point, rebooted my Linux system,
    # and things started working !  SNMP agent (snmpd) is working.
    sudo journalctl --unit='snmp*' --pager-end

  • Android agent apps:

    I don't see a FOSS SNMP agent app for Android. Is SNMP built into Android by default, or just not available ?

    Android "trap" app that sends to manager when some event happens:
    • "SNMP Trap" by Maildover LLC.

SNMP manager and client can be on separate parts (Wi-Fi and ethernet) of the same LAN.

Phone can NOT be using VPN-to-internet (at least, strongSwan the way I have it configured), when acting as a manager.

Linux system CAN be using VPN-to-internet (at least, OpenVPN the way I have it configured), when acting as a client.

Chris Siebenmann's "Some notes on finding and reading information over SNMP"
Chris Siebenmann's "Some notes on using snmpwalk to poke at devices with SNMP"

Mobile Device Managers (MDMs)

  • Desktop Central:

    Desktop Central
    Server runs on Windows only, I think.
    Agents available for ???

  • Spiceworks "Inventory":

    Server runs on Windows.
    Agents available for ???
    Scans by IP address. No mention of mobile devices.

  • Esper:

    Server runs on ???
    Agents available for Android only.
    More of a DevOps thing.

  • Miradore:

    Server runs on ??? Not Linux.
    Agents available for all but Linux.

  • Countly:

    Server runs on Linux.
    Your app on mobile has to be compiled with their SDK, to talk to server.

  • ITarian:

    Server ("manager") runs on Mac, Windows, Linux.
    Agents available for Android and iOS mobile devices.

  • Relution:

    Can use their cloud server (SaaS) up to 5 devices.
    Agents available for Android and iOS mobile devices.

  • AppTec EMM:

    AppTec EMM
    Server runs on ???
    Agents available for Android and iOS mobile and Windows Mobile devices.

  • ManageEngine:

    Server runs on Windows, but can use their cloud server (SaaS) up to 25 devices.
    Agents available for Apple, Android, Windows, Chrome.

At this point, I'm thinking of rolling my own solution: An agent on each client that just does an HTTP GET of the manager's web server every hour, passing in some information.
"MacroDroid - Device Automation" by ArloSoft Tools (easy to send IMEI and Battery%, not much else)

Syslog protocol

Teknikal's_Domain's "Graylog, and the Syslog Protocol, Explained"
Wikipedia's "Syslog"
RSyslog Documentation
Bozho's "The Syslog Hell"

Port 514 on UDP is simplest way.

# See if rsyslog service is enabled and listening:
systemctl status rsyslog --full --lines 1000
sudo netstat -tulp

# If not, enable and check again:
less /etc/rsyslog.conf
# Edit /etc/rsyslog.conf to enable UDP-514.  Then:
sudo systemctl restart rsyslog
# Then check again.

echo "<29>mymachine mycmd[2]: hello" > /dev/udp/
sudo grep hello /var/log/syslog

# Apparently, if the message starts with a date-stamp, that stamp
# will be used in syslog; otherwise rsyslog will add its own stamp.

# Change data to start with different leading value to end up in
# different log files.  Or omit leading "<nn>" entirely.

sudo apt install sendip

sudo sendip -p ipv4 -is -p udp -us 514 -ud 514 -d 'Hello' -v
sudo grep Hello /var/log/syslog

# In router admin, set a fixed address for your computer.  Then:
sudo sendip -p ipv4 -is -p udp -us 514 -ud 514 -d 'Hello Again' -v
sudo grep Hello /var/log/syslog

# Now go to Android phone and install app and send messages from there.
# This app works for testing purposes but mainly is logging
# its own internal failure msgs:

sudo tail /var/log/syslog
# If firewall is running on your computer, disable it or add exception for port 514.
# Probably have to disable VPN on phone.

# System log will aggregate repeated identical messages into
# one "repeated N times" message, which is a real pain while testing.
# Edit /etc/rsyslog.conf to set "$RepeatedMsgReduction off".

# Various rules in /etc/rsyslog.d/50-default.conf

# Client for Windows:

"snap install graylog"
"Edit /var/snap/graylog/common/server.conf to set the admin password and mongodb connection string. Connection information for elastic search is also needed."

Security Testing and Penetration Testing

Tightening Security

Really, it seems that 95% of the vulnerabilities are eliminated if you just don't run a web server on your machine. Also don't run incoming SSH or FTP or other login-type services, and keep software updated, and you're above 99%.

From older version of Easy Linux tips project's "Security in Linux Mint: an explanation and some tips":
"Don't install Windows emulators such as Wine, PlayOnLinux and CrossOver, or the Mono infrastructure, in your Linux, because they make your Linux partially vulnerable to Windows malware. Mono is present by default in Linux Mint; run 'sudo apt remove mono-runtime-common' to get rid of Mono."
[First run 'sudo apt --simulate remove mono-runtime-common' to see what else you'd lose.]

Ask Ubuntu's "What are PPAs and how do I use them?"
But: "One thing to keep in mind about using PPAs (Personal Package Archives) is that when you add a PPA to your Software Sources, you're giving Administrative access (root) to everyone that can upload to that PPA. Packages in PPAs have access to your entire system as they get installed (just like a regular package from the main Ubuntu Archive), so always decide if you trust a PPA before you add it to your system."

It's a good idea to get CLI mail working, and check it regularly, since various services and packages will send failure or security notices to root's email. See "Getting Linux local CLI mail working" section.

Easy Linux tips project's "Security in Linux Mint: an explanation and some tips"
The Empire's "An Ubuntu Hardening Guide"
lfit's "Linux workstation security checklist"
blakkheim's "Linux Security Hardening and Other Tweaks"
Madaidan's Insecurities' "Linux Hardening Guide"
Mehedi Hasan's "Best Linux Hardening Security Tips: A Comprehensive Checklist"
Mandiant's "Linux Endpoint Hardening"
Ubuntu Wiki's "Security/Features"
Privacy Guides' "Linux Desktop"
ArchWiki's "Security"
Maybe likely to break things:
SK's "How To Password Protect GRUB Bootloader In Linux"
[But that doesn't protect against booting from USB drive.]

See Linux section of my "Anti-Malware" page.

See Application Control and Security section.

Tightening Privacy


sudo bash

# To see accounts that can log in:
grep -v ':\*:' /etc/shadow | grep -v ':\!:' | grep -v ':\!\!:' | grep -v ':\!\*:'

# To see accounts that will be shown on the login page:
grep -v '/usr/sbin/nologin$' /etc/passwd | grep -v '/bin/false$' | grep -v '/bin/sync$' | grep -v '^root'

# To see home directories, if using systemd-homed:
homectl list

# To see accounts that can do "sudo":
grep sudo /etc/group

# To have "*" shown for each char of password you type to sudo:
sudo visudo
# then add ",pwfeedback" to the first "Defaults" line.
# You'll be in vim; arrow keys to get to place, "a" to append,
# type the chars, Escape to end, ":wq" to save and quit.

# To see failed login attempts:
sudo lastb

My understanding of accounts

  • There are "local" accounts (defined in /etc/passwd), but in a corporate environment there could be "network" accounts that are defined in a server somewhere (e.g. LDAP).

  • Generally there is a "local" home directory for each account (named "/home/USERNAME"), but in a corporate environment the home directory could be on some server, and just mounted onto the local mountpoint.

  • Login can occur on the system desktop GUI (display and keyboard and mouse), through system virtual console (TTY1; Ctrl+Alt+F1 to open, Ctrl+Alt+F7 to close), through Telnet/SSH from a network, through remote-desktop software such as VNC or TeamViewer.

  • The account you specified at installation time is a user that belongs to the "sudoers" group and thus can use the "sudo" command to do super-user things. You can login as that user.

  • There is a "root" account, but it is locked so you can't log in as root. No password can be typed which will match the value in root's password hash field.

    BUT: from Easy Linux tips project's "Security in Linux Mint: an explanation and some tips":
    "In Linux Mint 18.3, the root password is unfortunately no longer set by default. This means that a malicious person with physical access to your computer, can simply boot it into Recovery mode. In the recovery menu he can then select to launch a root shell, without having to enter any password. After which your system is fully his. So, set a password for root (preferably identical to your own password)."

  • There may be a "guest" account, and you can log in as that user. [Disabled by default on Mint 19.] There is no password on that account. Can it login through SSH ?

    Definitely disable guest login, and you have to reboot after doing so. In Mint, run "System Settings", go to "Administration" section, click on "Login Window", click "Users" tab, probably everything should be turned off.

    Abhishek Prakash's "How To Disable Guest Account In Ubuntu"
    Ubuntu's "CustomizeGuestSession"

  • If you create more users, you can choose to add each new user to the "sudoers" group or not.

  • If you are logged in as a user who belongs to the "sudoers" group, you can do any administrative operation, and the password to use when "sudo" asks is the password for that user.
    Sudo make me a sandwich

  • I guess it is okay to routinely log in and do all your daily computing as the user you specified during installation, which belongs to the "sudoers" group. Any malware you run accidentally would have to know your password in order to do "sudo" and then do administrative stuff, and I think sudo accepts password only from keyboard. So it's not quite like routinely running as Administrator under Windows.

  • On a single-user system, the security distinction between root and normal user is not so important. All of the interesting personal files probably are owned by the normal user. So if an attacker can get in as that normal user, they get all the good stuff, no need to escalate to root.

    Escalating to root might let the attacker do a few more things, such as access network hardware at a low level to attack other machines on the LAN.

    Escalating to root on a multi-user system is much more serious/important than on a single-user system.

  • From someone on reddit:
    "Normally, all keyrings should get signed into automatically upon user login to the system. If suddenly you have to log in to a keyring when you never did before, what's gone wrong is that you changed the password with passwd instead of using the account manager built into the GUI. The GUI will automatically change your keyring password too. The command line won't."

Ubuntu's "RootSudo"

Some command-line ways to list all users: "getent passwd", "compgen -u", "cat /etc/passwd".

List users with no password set: "sudo awk -F: '($2 == "") {print}' /etc/shadow"

List users with UID set to 0 (superuser): "sudo awk -F: '($3 == "0") {print}' /etc/passwd"

List info about a user: "id USERNAME"

Set limits on users or groups: /etc/security/limits.conf

Login security can be defeated if attacker has physical access:
Alarming article about (a hole in) account security:
Abhishek Prakash's "How to Reset Ubuntu Password in 2 Minutes" (boot into Recovery mode)
Maybe there is some way to password-protect GRUB, or maybe this doesn't work if /home is encrypted ?
SK's "How To Password Protect GRUB Bootloader In Linux"

Another way to change passwords if you have physical access: boot the machine from a Live system on USB or CD, do "sudo -i", do chroot to the main system disk, do "passwd $username".

Ask Ubuntu's "How do I reset a lost administrative password?" (boot into Recovery mode)
SK's "How To Reset Root User Password In Linux"

Not sure, but I think these methods work even if user's home is encrypted. Access to the disk encryption passphrase is controlled by the user permissions, so once you login as the user (with any or empty password), software can decrypt the user's home.

PAM (Pluggable Authentication Modules)

Applications (including the "login manager" and sudo) can be written to be PAM-aware. Then the application doesn't have to invent its own authentication mechanism.

The authentication process can be complex and multi-step. But as far as I can tell, all it does is give a yes/no for access to the application; there's no way to have it do fine-grained control of access to permissions within the application ? To do that, you'd have to define separate users with separate permissions ?

Configuration files are in /etc/pam.d directory (which override the files in /usr/lib/pam.d). Some are for applications, others for events.
"apt list | grep libpam | less"
"eopkg list-installed | grep pam | less"
"man pam"
PAM can limit resource usage via settings in /etc/security/limits.conf
PAM can enforce password strength rules via libpam-cracklib and /etc/pam.d/system-auth
PAM can lock an account after N failed login attempts via pam_tally2 and /etc/pam.d/system-auth

Mokhtar Ebrahim's "Configure and Use Linux-PAM"
Kennedy Brian's "Basic Linux PAM Modules"
Kevin Reursora's "Linux PAM Tutorial"
Waji's "Linux PAM Framework"
Chris Siebenmann's "Understanding the effects of PAM module results"
Chris Siebenmann's "The practical problem with /etc/pam.d on long-lived Linux systems"
Good info in Chapter 23 "Understanding Advanced Linux Security" of "Linux Bible" by Christopher Negus.
Old but some useful stuff: Debian Reference's "Chapter 4. Authentication"

To enable TOTP on desktop logins:
If you're going to enable this, I would save a copy of "/etc/pam.d/lightdm", then create another user account, login to that account, and enable TOTP on that account, to make sure everything works.

Chris Hoffman's "How to Log In To Your Linux Desktop With Google Authenticator"
Daniel Pellarini's "How To Configure Multi-Factor Authentication on Ubuntu 18.04"
nixCraft's "Secure Your Linux Desktop and SSH Login Using Two Factor Google Authenticator"
Linux Uprising's "How To Login With A USB Flash Drive Instead Of A Password On Linux Using pam_usb"

"sudo apt install libpam-google-authenticator".
"man google-authenticator".

nuvious / pam-duress

Polkit / PolicyKit

"a service running on D-Bus that offers clients a way to perform granular system-wide privilege authentication ... Unlike sudo, that switches the user and grants permission to the whole process, polkit delimits distinct actions, categorizes users by group or name, and decides whether the action is allowed or not. This is all offered system-wide, so that D-Bus services can query polkit to know if clients have privileges or not."

Venam's "D-Bus and Polkit"
ArchWiki's "Polkit"

sudo systemctl status polkit --full --lines 1000
systemctl status | grep policyk
sudo ps -ax | grep -E 'polkit|policykit' | grep -v grep

man polkit

ls /etc/polkit-1/rules.d
sudo ls /usr/share/polkit-1/rules.d
ls /usr/share/polkit-1/actions

XDG Desktop Portals

Tweaking sudoers

Edit /etc/sudoers file (maybe use "sudo visudo"):

# For USERNAME, sudo never ask for password:

# For USERNAME, for CMDPATH1 and CMDPATH2, sudo never ask for password:

Sk's "How To Run Particular Commands Without Sudo Password"

Keyrings / GnomeKeyring / ksecretservice

setevoy's "What is: Linux keyring, gnome-keyring, Secret Service, and D-Bus" (also Arseny Zinchenko (setevoy)'s "What is: Linux keyring, gnome-keyring, Secret Service, and D-Bus")

Various keyrings or caches:
  • Linux kernel keyring:
    "man 7 keyrings"
    "man session-keyring"
    "man user-keyring"
    "man process-keyring"
    "man thread-keyring"
    "keyctl show"
    "keyctl list @us"
    "keyctl print @us"
    "cat /proc/keys" to see some of the keys in the Linux kernel keyring.
    Keyrings(7) man page

  • GNOME Keyring:
    GNOME Keyring
    Creates ~/.pki directory tree (also could be created by Chrome/chromium) ?
    swick / mozilla-gnome-keyring (extension for Firefox and Thunderbird)
    From GNOME Keyring - Security FAQ:
    "GNOME Keyring is integrated with PAM, so that the 'login' keyring can be unlocked when the user logs in.".
    LZone's "Using Linux keyring secrets from your scripts"
    GNOME Keyring
    Arch Wiki's "GNOME/Keyring"
    Nurdletech's "GNOME Keyring"

    GNOME keyring is stored under ~/.local/share/keyrings

    If you keep getting prompted for password to unlock keyring, and you don't want that, delete the (default ?) keyring inside ~/.local/share/keyrings and then next time you're asked for password, set an empty password.

  • KDE Wallet:
    "man -k kwallet"
    "KWallet isn't a password manager in the traditional sense like Bitwarden or Lastpass. It simply manages the user keyring, which serves as a storage area for apps to store their secrets in an encrypted way."

  • systemd-creds:
    "systemd-creds list"

  • App-internal keyrings:

    • Thunderbird internal keyring:
      Thunderbird OpenPGP Key Manager ?

    • MySQL internal keyring:
  • System GnuPG Keyring:
    "gpg2 --list-keys"
    "gpg2 --list-secret-keys"
    "man gpg"
    "man gpa"
    Jack Wallen's "How to encrypt a file on Linux" (GPG and Seahorse)

  • ssh-agent:
    "man ssh-agent"
    Not persistent across reboots; starts up empty each time.

    Is integrated with ssh, sftp, scp, PAM, Chrome, chromium ? Can be integrated with Git, GnuPG, Firefox ?

    KeePassXC password manager can supply SSH keys to an SSH agent: KeePassXC and SSH.

    Run "ssh-add -l" or "ssh-add -L" to see all keys available through ssh-agent.
    Run "ssh-add -s filename.pkcs11" to add a digital certificate to ssh-agent.

  • SSSD (System Security Services Daemon):
    Cached credentials fetched from back-end systems (providers) such as LDAP, Active Directory, or Kerberos.

    Red Hat Training's "Configuring SSSD"

  • Network Manager:
    Stores credentials for connecting to Wi-Fi and VPNs.
    Maybe uses system keyring ?
    nmcli can act as a NetworkManager secret agent or polkit agent, or both.

From someone on reddit:
I think the various keyrings mostly are used for different things. The linux kernel keyring is used for internal key management, while systemd-creds is used for system services and units, and gnome-keyring/kwallet is a graphical way of managing the user's passwords and keys. GPG is more of a backend for signing stuff, and can be used in Thunderbird or similar to verify identity of the sender of emails, or for verifying packages in your system through the package manager and the repos. ssh-agent is a front-end for managing ssh keys, there are others available too such as the gnome-keyring. SSSD I haven't ever used, and networkmanager I think stores passwords either in the user's keyring or in plaintext in the system configuration, depending on how a connection is configured (i.e., "for all users" or "only for me").

Places passwords are stored:
GNOME networking passwords are stored in plaintext in files in /etc/NetworkManager/system-connections

MEGA password discussion
MEGAchat: Technical Security Primer

Managers / apps:
  • Linux kernel keyring: "Passwords and Keys" application (AKA "Seahorse"):
    Accesses GNOME Keyring.
    AKA Seahorse

    Under Passwords - Logins, it seems to have a bunch of placeholder entries for web sites, and a couple of things for apps (Chrome, Skype). There's nothing (for me) under Certificates (I do have certs installed in FF, Chrome, Thunderbird, but they don't show up here), and under Secure Shell (OpenSSH = ~/.ssh). But there are several keys under PGP Keys (maybe stored under ~/.gnupg directory ?). Hover mouse over each item to see tooltips.

    Jack Wallen's "How to encrypt a file on Linux" (GPG and Seahorse)

  • Kleopatra:

libsecret-based clients via the secret storage DBus API ?
KeePassXC 2.5.x can be used as a vault service by libsecret: KeePassXC as "secret service"

"nmap --script ssl-cert localhost" gives me one cert used by port 25 SMTP, called "mint" or "DNS:Mint".

"nmap --script ssl-enum-ciphers localhost" gives me TLS ciphers used by port 25 SMTP, port 631 CUPS.'s "Kernel Key Retention Service"
Oxana Kharitonova and Ignat Korchagin's "The Linux Kernel Key Retention Service and why you should use it in your next application"

Also see "Certificates And PKI" page

Security Test / Audit

David Mytton's "80+ Linux Monitoring Tools for SysAdmins"
Daniel Miessler's "A tcpdump Tutorial and Primer with Examples"
"sudo tcpdump -i lo -A | grep Host:"
netstat: "sudo netstat -atupl"
lsof: "sudo lsof -i" to see established connections.
Mehedi Hasan's "40 Simple and Effective lsof Commands"
ss: "sudo ss -lptu".
NixCraft's "ss command: Display Linux TCP / UDP Network/Socket Information"
NixCraft's "Linux: 25 Iptables Netfilter Firewall Examples For New SysAdmins" (see "27. Testing Your Firewall")
nethogs: "sudo nethogs"
Clement 'Tino's "Linux Password Mining"

CERT's "Intruder Detection Checklist"

See the Port scanning or router testing section of my Testing Your Security and Privacy page.

SEI's "Steps for Recovering from a UNIX or NT System Compromise" (PDF)


Throttling network bandwidth, for testing purposes:
"sudo tc qdisc add dev enp19s0 root tbf rate 32kbit latency 50ms burst 770"
"sudo tc qdisc delete dev enp19s0 root"
Linux Foundation's "netem"
SoByte's "Introduction to Linux TC Flow Control"
leandromoreira / linux-network-performance-parameters

Brendan Gregg's "Linux Performance Tools" diagram