460 comments

[ 3.2 ms ] story [ 181 ms ] thread
As an experienced RHEL admin, a few years ago I probably would have said this is very bad advice in any professional context, and you should spend the time to learn it because it will save you one day.

Now, I think my advice would be: Put everything in a container, and learn how to run Docker or Podman (or k8s) in a secure way (ie no root containers, be very careful with volume mounts, etc). Yes, they aren’t as mature as SELinux, but containers aim to provide many of the same benefits that SELinux does (and even more) except in a way that’s much easier to manage. Even better is that these container runtimes often come with SELinux and AppArmor policies out of the box on good Linux distros.

I was about to argue with you until I read to your last point. Totally agree one of the great things about containers is indeed they integrate very well with various Mandatory Access Control implementations SELinux included and don't generally require specialized policies for each app.
I agree that containers are easier to manage than SELinux, but still not easy enough. Linux provides many low level primitives for restricting applications and SELinux, Apparmor, Docker, Flatpak, and systemd all provide high level abstractions for those. But IMHO none of them really finds a sweet spot between flexibility and usability. `systemd-analyze security` for example lists 80 (!) different settings, even though some of them are very high level such as `ProtectSystem`.

Containers have made the conceptual shift from allow/deny to isolate/share. Somehow this feels better even though it is effecitvely the same.

I am still waiting for an abstraction that uses all the low level features and wraps them in a high-level interface that puts usability front and center.

I am not sure if this is even possible though because many applications are not built with sandboxing in mind. Adding another file somewhere on the system that needs to be accessed is not considered a breaking change by most. So maybe we need a more fundamental shift.

> I am still waiting for an abstraction that uses all the low level features and wraps them in a high-level interface that puts usability front and center.

Bubblewrap? FlatPak's sandboxing features are built on it already.

In my opinion, if an application requires more access than a docker container gives by default, then that application should probably just run in a VM. If the application needs more access because it needs to manage or control some hardware, then it should be tailored to the O/S and have a small core service that runs naked under systemd or whatever. If fancy management of that core service is needed, it can expose a port that an application can talk to, that's safely isolated in a docker container.

Maybe that's just daydreaming about a perfect world, but I agree that it should be easy to reason about the access levels.

What about an application like vim? It should be able to access any file I pass that is explicitly opened, but not much more. That is hard to express with current tooling.
You could do it with a file picker API that opened an out-of-process file picker. I'm pretty sure this is how WinRT works. Would be tricky for a purely command line workflow, but very doable with a GUI.
Even file picker APIs are severely lacking with regards to any multi-file filetypes, where opening one file means having to subsequently access further additional files, too (but which files exactly cannot necessarily defined in advance because it depends on the contents of the initially opened file).
You shouldn't run an application like vim in Docker. Unless your server is running Vim as some sort of service, in which case it should only open files in a volume you bound to it.

Vim is exactly the kind of application you would run in a virtual machine.

You are describing the Flatpak security model. Flatpak was invented for interactive applications like this.
And when everything is in docker you can use SELinux again: A docker container is not allowed to access the host system or access the filesystem of other containers. That‘s the default. SELinux protection without any weird problems.
Container approach is not always feasible, for example when you need to stay on bare metal. There are Linux applications where selinux definitely gets in your way and there are legitimate reasons to turn it off completely.

edit: I like how I'm getting down-voted for sharing factual information. No-one in high frequency trading employs containers because it doesn't help soft-realtime, low-latency goals. There are other performance-sensitive domains where containers aren't an option. Sometimes I feel like this place is turning into Reddit.

> when you need to stay on bare metal

What cases can linux containers not handle? Containers can access GPUs, /dev/kvm, block devices... I'm having trouble thinking of anything they can't do. After all, they're just processes in a glorified chroot, not that different from processes on the linux host.

Not sure about need but I do remember it being a pain in the ass to run anything that expects to be managing docker inside docker. Things like self hosted gitlab ci where its trying to start up containers itself.
> ...anything that expects to be managing docker inside docker.

Now that's an interesting problem to have!

If you trust those tools and don't have untrusted users or untrusted code, you can sometimes just mount /var/run/docker.sock and use the VM/VPS/server's Docker directly. It is actually the approach that was used by excellent tools like Portainer, though it's also really risky as well.

Alternatively, you can try to just run Docker in Docker (DinD), which is a bit more tricky and the opinions there are split about whether to do it and when to do it: https://github.com/jpetazzo/dind

Of course, someone might also jump in and suggest that Docker is architecturally problematic (i don't care much, just want my containers to run, then again; i don't deal with untrusted code or any sort of multitenancy) and you should use Podman or another set of technologies, which is interesting advice but would necessitate other approaches.

In short, like with most technologies: Docker and OCI container in general get more messy as your requirements become more advanced. For the problems that they do solve easily (app packaging), they are pretty good, though!

Mounting the docker socket into a container works.

If it's advisable is another question, as that gives full control over all other containers (and likely more)

Mounting the docker socket makes it trivial to escape to the host since you can just launch a privileged container or mount arbitrary files. Plus the daemon generally runs as root.

At that point you may want to just run it on the host, but basically you'd better trust whatever it is.

Ultra-low latency applications on Linux are definitely one domain were containers are a big no-no for performance reasons. In my field (HFT) you won't find any serious performance-sensitive deployments using containers. So that's one example.
Why would a container increase latency? It's just a pointer on a process. It's there on all processes.

https://elixir.bootlin.com/linux/latest/source/include/linux...

https://www.diva-portal.org/smash/get/diva2:1252694/FULLTEXT...

Also docker NAT will add significant latency if you don’t use host network mode.

When microseconds matter, everything matters. Any intermediate program would be suspect.

Then that's not about containers, but about NAT. So maybe don't use NAT. You can have NAT on the host, too, and it would slow down things also.

"Container" (namespace to be precise) is not really an intermediate program, it's a state associated with any Linux process.

Are you referring to kube rather than containers?

A container is just namespaces and cgroups. You can still have your mellanox or solarflare zero-copy network stack for a containerised process.

That is, a containerised user space process can directly access the hardware, bypassing the kernel but isolated from other processes.

There are plenty of footguns for sure though but my experience working in HFT has been everyone is pretty elite skill-wise so sharp edges are not an issue in practice.

I've had quite some problems setting up DPDK and other device drivers inside of containers. It looks like it should be easy, yes, but then reality hits you in the face.
A couple sysadm red flags:

1) The article author is Testing in PROD

2) selinux debugging relies on auditd, so sanity checks required.

  df -P /var/log/audit # has space?
  tail -1 /var/log/audit/audit.log # is recent?
  semodule -DB  # disable dontaudit
  setenforce 0
  # run the failing test
  audit2allow -l
After which the selinux debugging experience boils down to:

    mk_semod() {
        module_name=$1; shift
        audit2allow -l -m ${module_name} -a > ${module_name}.te
        $EDITOR ${module_name}.te || return
        checkmodule -M -m -o ${module_name}.mod ${module_name}.te
        semodule_package -o ${module_name}.pp -m ${module_name}.mod
        semodule -i ${module_name}.pp
    }
I think you just proved the author's point. That looks entirely inscrutable.
As a lightweight alternative to Docker-based (or any container-based) solutions: Try firejail. You can set up a directory that will be the "home" of the sandboxed application you're running, then you can do something like `firejail --private="${HOME}/my_firefox_jail" firefox`. There are built-in profiles for many applications already, and you can customize them (by adding `.local` files, not editing the existing `.profile` files). See the following link for details.

https://wiki.archlinux.org/title/Firejail

Convenience matter. Without it being automatically on everywhere, it doesn’t protect from much. Sure it can be good for the occasional random software you trust the least, but how many exploitable bugs were found in any of your completely trustable tools?

Also, afaik firejail runs as suid, making any possible escape much more serious.

[1] discusses firejail running as root:

> For a server, the process exposed to the outside world runs as an unprivileged user (unbound or nobody). The process is started by a separate process running as root (as explained by @Ferroin above). The starting process is never exposed to outside.

> The same is true for Firejail. By the time the unprivileged server process starts, Firejail is already sleeping.

And I think Docker has a similar problem as mentioned in the "warning" section in [2]:

> Warning: Anyone added to the docker group is root equivalent because they can use the docker run --privileged command to start containers with root privileges. For more information see [3] and [4].

[1]: https://github.com/netblue30/firejail/issues/1720

[2]: https://wiki.archlinux.org/title/Docker#Installation

Actually docker is much worse due to the large attack surface.
Hum, as another admin... No thanks.

With IllumOS I can agree on zones, I can partially agree on lpar on AiX, I can accept GNU/Linux limits with cgroups. Enlarging the attack surface to follow the current wannabe Gurgle mania... No. Like no in the recent past to full-stack virtualization on x86 to enrich VMWare, buy big desktops sold as powerful servers just to play matryoshka doll for someone else business...

Of course, it's hard to satisfy hw "subdivision" vs sw subdivision, in the past we have tried the hw path with blades for the small side, infiniband and co for the large side and both proved to be not very scalable but the issue is in actual OS design and can only be solved changed that: An OS mush be a single application, with internal namespacing, networking. We have seen it in various past OSes. It's about time to make them again accepting that the IBM model is good only for IBM, witch means for selling stuff to people having no choice but buy or ignoring something better can be done.

Can you elaborate on the scalability problems with infiniband?
It's not a problem with infiniband but a problem of sw mutating needs vs actual hw assets: matching is hard. Hw cost money so anyone try to be moderately tight, looking at life expectancy and supposed sw changes in that timeframe, but hw and sw have different lifecycle. At a certain point in time sw infra change while hw is still the same, at another point in time available/current iron change but software on it remain the same.

In classic times that's just a matter of balancing both, carefully designing both, but in modern time developers just "produce code", operation is pushed aside, communications are constrained often by the policies and the result it's a mess => companies choose "the cloud" witch means outsource the issue to third parties. Those third parties count on the fact that even if anything change in the end a computer is always a computer so they can live on a changing world because if single companies have irregularly changing needs on average the rate of change is similar. Also on scale redundancy needs lower the costs and that's why we switch from classic big iron to desktop crap packed in racks. Now we start seeing more and more the limit of such model, and no solution is here.

Big iron is long lost, now way to expensive not much in absolute terms but in demand terms: try to sell a Power system, the customer look at specs and say "hu?! a couple of PCs from nearby grocery store are equally powerful!". Such iron modularity coming from classic mainframes (infiniband in the end is crylink changed a bit by SGI and others) is considered too expensive, on the other side of the spectrum small-board ARM super-blades tentative still results in fails.

Until we accept that hw and sw can't really be two separate world and both must be open to being able to interoperate on scale we will not find any really scalable solution.

Sw side it's not different: these days is the containers mania days because after many have suffered burn with full-stack virtualization on x86 they look for something with less overhead and equal design: hw-sw decoupled, possibility of run an infra you do not know buy pre-made images/containers from third parties who maintain them without needing to know your infra. The result again is an enormous amount of layers and giant attack surface no one really know how extended it is. Since coms are needed we punch holes here and there, and on the other side "safety features" arrive to compensate, making more complicatedness layers on complicatedness instead of admitting the basic issue: in sw terms our OSes are badly designed for current needs, they are a relic form a long lost past where they aren't even good but just cheaper alternatives to something better.

If we ever admit those errors probably we will be able to design modular iron and modern OSes marginalizing those issue, but so far no one want such a nightmarish adventure...

I'm guessing part of the problem infiniband switches get expensive AF when you're going for 32x100 or rack-level anything. And you're still bound to up to 200Gbit per link (and the cpu load that entails) or lower bandwidth bonded links, why is not as interesting as QPI.

Aside from purely guessing I'm interested in scalability pains war stories with infiniband too :-) as I'm looking into a 400GbE-everywhere datacenter build...

AppArmor is great. It can do much of what SELinux does, but it uses plain configuration files as opposed to incredibly obscure and clunky filesystem-level hacks.
It still has the same gotchas as a user though.

I was daemonizing a uvicorn (Python) process using systemd and could not get the Python script to write its log file anywhere. Not the current directory owned by the user, not elsewhere, and no errors showing up in the system logs.

After a few hours banging my head against the wall I discovered systemd's ReadWritePaths. Once I set that, it would log to any directory I specified.

It's the only service I've created where this has been necessary, and others write logs, so I have no idea why this one caused errors. If I did something wrong, let me know how this should be handled.

Most systemd services log to stdout and let systemd put it in the journal, or they log to syslog and let systemd put it in the journal. Most don’t write their own log files any more. I really recommend going that route because it is nice to be able to search the journal, especially if you provide extra metadata for each log message.

It sounds like you were using the DynamicUser=, ProtectSystem=, or ProtectHome= settings which can greatly limit where a service is allowed to read from and write to and thus require you to open specific directories back up. Instead of using ReadWritePaths=, you might prefer to set LogsDirectory=.

Yet another rabbit hole has emerge. And it is called “systemd”.

What a great time to be a Linux system administrator.

Compared to selinux, though, the systemd documentation is excellent, and the tools for observing the state of the system are very good.
How does this work when you want to log different things? Like if I had a web server, I wouldn't want the server log and access log to go to the same place. Sure, I guess I could send one to stdout and the other to stderr, but what if I have three things?

Maybe systemd/journald supports this use case by forcing you to adopt some sort of structured log format that you emit to stdout, but I don't think I want to have to conform to whatever journald wants me to do, unless it's standardized and well-supported among various logging tools.

Journald indeed supports structured logging.

Try `journalctl -o json` to see all the fields that get logged. Applications can add more.

So it very much means that a webserver logging to journald can already provide it all with fields for the vhost, status, URL, referer, and whatnot, and you can just search the log by that and don't need to do your own parsing.

Fair, but still annoying. The simple solution, that always works, is to write separate streams to separate files. At least journald supports JSON, and not some proprietary format, though I imagine the particular fields it supports might not be supported by other logging systems.

I'm just tired of all this added complexity, when I don't really see much of the benefit.

The point is that you can include arbitrary metadata of your choosing, in addition to the standard fields that journald keeps track of for you. For example, if you include the id of the logged–in user with every message, then when they complain about a bug you can query the journal to find exactly what they did without any noise from all your other users. And you don’t even have to pay a SaaS company for the privilege.

> I'm just tired of all this added complexity, when I don't really see much of the benefit.

There is a lot less for each application to implement on its own, such as log levels, timestamp format, log rotation or even just the paths where logs should go. Instead those details can be configured by the system administrator using a uniform interface across all applications.

> It sounds like you were using the DynamicUser=, ProtectSystem=, or ProtectHome= settings which can greatly limit where a service is allowed to read from and write to

Thank you! I have DynamicUser set - I can't think why I added it here, perhaps no reason at all - and that is the difference to previous systemd services I've written. I did not know it had such an effect on behavior.

It is a nice security measure; it means that no other service can accidentally read or write to the same files. An older form of the security measure was to create new system users like “ftp” and “mail” so that the ftp daemon couldn’t be tricked into overwriting someone’s mail queue and so on. The downside is that this takes a certain amount of effort on the part of the system administrators and distros to arrange; the bookkeeping becomes a significant source of manual effort.

The DynamicUser= setting tells systemd to invent a new user on the spot, with an id that is not in use by any other service. You can add as many such services as you like¹ without having to do any extra work to keep /etc/passwd updated.

¹ as many as you like as long is it isn’t more than several thousand, unless you recompile systemd with larger limits.

This is a selinux gotcha, not an apparmor one, right?
No, this is happening with apparmor on an Ubuntu 20.04 server.
I feel stupid --- ReadWritePaths= is a systemd feature, not an apparmor one, so how exactly is it an apparmor problem?
AppArmour assumes everything is allowed unless it is explicitly denied by policy, SELinux assumes everything is banned unless it is allowed by policy. This makes SELinux fundamentally more secure because unlike apparmour you cant forget to deny some access that leaves you wide open, instead you forget to allow things and your app breaks. It also makes SELinux more complicated to implement because you have to allow everything you need or your app breaks whereas apparmour lets you deny the things you're worried about and ignore everything else.

SELinux also supports interesting things like applying security levels and contexts to data, so you can have data that is only accessible to appropriatly cleared users in one department but not to people with similar clearances in other departments. Very few people use this stuff though.

Selinux uses extended attributes to store its labels which is a pretty standard way of associating metadata with objects, and is supported by most standard unix commands (via the -Z flag) so I'm not sure what you mean by "filesystem hacks". Fundamentally they are both implemented as security modules in the kernel and do pretty much the same thing, which is best depends on whether the added security of SELinux is worth it to you.

> AppArmour assumes everything is allowed unless it is explicitly denied by policy

No, AppArmor uses a whitelist approach as well for its profiles. "Deny" rules are used in exceptional cases.

> SELinux also supports interesting things like applying security levels and contexts to data, so you can have data that is only accessible to appropriatly cleared users in one department but not to people with similar clearances in other departments.

AppArmor has subprofiles and variables that can be used for this approach.

I'd generally agree with this, but for production use (where it'll be CRI-O or ContainerD in all likelihood) it's worth noting that using containers does increase your attack surface.

We've had container breakout CVEs in the Kernel+ContainerD+CRI-O this year, and the ContainerD/CRI-O ones were not complex at all, so you do need to stay on top of patching as well as the other good practices mentioned.

A lot the container breakout CVEs do not affect a system that uses SELinux properly.
have you seen an analysis of SELinux against the recent set of breakouts? That'd be interesting to see.

Definitely the CRI-O one (which is most likely to affect Red Hat based systems) was able to exploit a default OpenShift cluster in my testing.

> Put everything in a container, and learn how to run Docker or Podman (or k8s) in a secure way

Or just use Qubes OS: https://qubes-os.org.

As a completely new admin, could you elaborate on "be very careful with volume mounts"?

In the k8s env I run, the filesystem is backed by ceph, which creates persistent volumes that the different pods can claim. Is it just "be careful not to mount docker.sock"?

> but containers aim to provide many of the same benefits that SELinux does

Absolutely not. They are not designed as security tools in the first place. Especially docker, with its huge attack surface.

You are confusing containers with sandboxes.

Furthermore they don't implement anything resembling RBAC.

Docker actually comes with an apparmor config that disallows you to interact with any files outside of the container. It's not a so strong guarantee compares to inode based approach (selinix), but is still much better than don't have one.

And if you enables uid mapping, your permission in the host system is just as high as nobody if there isn't a kernel exploit happened somewhere.

But the fact it is nobody is also problematic, because dir mount will be almost alwyas read-only now.

It comes with both an apparmor profile and an SELinux profile. What gets used depends on what's on the system... and I guess you need to actually set the flag on dockerd to enable SELinux.
> much easier to manage

I would say it's not necessarily easier to manage, but it's much easier to understand, because containers create natural borders between the different software running on the machine.

By using containers you can multiply your security problems!

That is, it does nothing to address security problems latent to each container binary.

> There’s nowhere on the system where you can view the policies and look up why something might or might not work.

I always thought I had to be missing something with SELinux because this is what it seemed like to me and that can't be right. My impression is that the documentation for SELinux is extensive in all of the areas that aren't affecting you but it's really hard to nail down exactly what the policies are, what labels are available, which labels you should be using, and generally how everything interacts. Is there a SELinux Wiki somewhere that I've missed that has a simple breakdown of each and every possible label with interactions? Some tool I can use to generate said list?

You can install the policy source. It ain't easy but it's there.
sesearch lets you query the rules on a system.

sesearch -A will show you every thing that is allowed, and gives you (a lot of) lines like:

allow httpd_t httpd_t:dir { getattr ioctl lock open read search };

Which says that things (i.e. processes) with the httpd_t label are allowed to perform getattr, ioctl, lock, open, read, and search operations on directories with the httpd_t label.

ps -Z and ls -Z will then list the labels of processes, and the labels of files and directories. If your processes label does not have an allow rule for your file label for the correct action you are denied.

The only trick really is that when it reports a label as say "system_u:system_r:httpd_t:s0" thats 4 different colon separated fields and the only one you really care about is the type field "httpd_t", because thats what the rules are defined for (unless you're the NSA or doing Very Interesting things (the other fields are user, role, and security level, but the default Red Hat etc selinux policies dont use them))

There is no wiki with definitive list of labels because they are just strings and the policy writer can call them what they like, even the _t suffix is just a convention to denote the type.

I came to the same conclusion, but in my case the problem was that there were no audit messages for one particular denial. After a week or two of investigation I finally found the solution. But, I decided that I simply couldn't trust selinux any more, so I turned it off.
I like apparmor better. Set it up for high attack surface apps like browsers and vms.
I can't say my apparmor experiences have been great. SELinux and Apparmor are just two heads of the same problematic coin. As other comments on here point out, it's easier to have one sane policy for docker and containerize everything else.
How is your docker policy not something like: “give docker access to everything” ?
How the hell do I dockerize firefox or vbox? I get it for server workloads but I was talking from a desktop perspective. Even if that is possible seems like even more stuff to manage and troubleshoot.

Also, you are not supposed to ise containers as a security boundary??

Everyone who has even a slight interest in learning how to use selinux should just go through this CTF-style game: http://selinuxgame.org/
Ironic (maybe intentional?) that this site doesn't use TLS.
There's something funny about a website about teaching security practices being unavailable through HTTPS.

It looks like the website is hosted by github pages, and the author didn't bother setting up SSL correctly.

Is there anything on the site that needs to be secured with TLS? There's no authentication, no user details, why would it need to be secured?
So that your ISP, or someone else along the way, doesn't put a cryptocurrency miner into the page source.
Someone in the middle could teach you a variant of the material in hopes of creating more insecure servers out there. Or perhaps link to an "official companion app|pdf|exe" on the page.
Or more likely: insert a cryptocoin miner script or ads.
Using HTTP leaves you open to being mitm'd, for one.
Why would you need SSL/HTTPS for a casual game like this?
It's free to set up. Justify why it can't be https.
Lots of things are free. Doesn't mean you need to do them. The burden of justification lies on the people advocating for adding complexity and dependency to a simple system.
It’s not complex. You click a button on GitHub. So gaining a decent amount of security and privacy easily justifies the work of clicking a button.
The Vagrantfile, but otherwise your right.
Because plenty of unscrupulous ISPs and governments log unencrypted web traffic. Some ISPs use that information for advertising, or inject custom javascript into unencrypted web pages their customers visit for who knows what reason.

HTTPS is free and stops most of these tricks from working. You can still sniff the domain name via DNS or SNI, but HTTPS blocks attackers from seeing the URL you're visiting, or seeing the traffic the server sends back. It also stops people from doing MITM attacks on the connection.

Its 2022. HTTPS is fast, it works great and its free. Use it everywhere.

> Because plenty of unscrupulous ISPs and governments log unencrypted web traffic.

Ok. Not relevant here. I don't care if my ISP knows I'm learning SELinux. And they would know that even with HTTPS.

> Some ISPs use that information for advertising, or inject custom javascript into unencrypted web pages

Sounds like an ISP problem. Buy service from a better one. No need to impose SSL on the website for this.

> HTTPS is free

Absolutely not. It takes time and effort to set up. And then maintain forever. Plus you're introducing an unnecessary dependency on multiple third parties.

> HTTPS is fast

HTTP is faster.

>Sounds like an ISP problem. Buy service from a better one. No need to impose SSL on the website for this.

Just move I guess.

Or don't. It's not a problem that needs to be solved server-side.
It is a problem to solve over the wire, because we should assume at this point that bytes over the internet are monitored. Both in the east (Great Firewall of China) and the west (NSA + Snowden). I don't want my ISP or my government knowing which websites I'm visiting, what apps I open on my phone or, really anything else about me without a court order. Insecure-by-default is a bad default.

To protect users, traffic over the internet should always be encrypted. Even if you don't care, as a user I care. And thankfully the people in charge of our software, protocols and ecosystem are slowly forcing the issue on our behalf:

- Unencrypted http will eventually be deprecated from web browsers. (Newer browser features are already banned in insecure contexts).

- iOS forbids applications from making unencrypted HTTP connections.

- The IETF more or less requires new protocols to be secure.

We'll see more of this over time. Its a good thing. Get on board.

> HTTP is faster.

Thats not always true, thanks to awful middleware boxes. Especially inside corporate networks.

Also TLS is required for http2 - which is much faster than HTTP1.1 in almost every case.

> It takes time and effort to set up. And then maintain forever.

People level the exact same accusations at SELinux. Some would say SELinux doesn't add a lot of security, and its a pain to set up and maintain.

HTTPS is much easier to set up than SELinux thanks to letsencrypt and certbot. And it adds real security for your users. Its weird to promote SELinux but not bother with TLS.

But all these complaints are moot in this case anyway because this website is hosted by github pages[1]. Github will do all the heavy lifting to make HTTPS work. The owner just needs to set DNS up:

https://docs.github.com/en/pages/configuring-a-custom-domain...

Oh yeah and you know what I was saying about http2 being faster than http1.1? Github enables http2 automatically on github pages. But only, y'know, if you set your site up correctly.

[1] At least according to the invalid cert warnings I'm seeing

What is the concern with these logs? Do they contain end user information? May be IP, anything else?
Also technology wise its not 2022 everywhere, if you know what i mean. Many poorer nations suffer from inferior infrastructure, which could mean slower loading / processing times for https based webpages.

I remember reading an article along these lines a few years ago when arguing against using https absolutely everywhere.

Nope. SSL was pretty okay performance-wise 15 years ago. So no, we don't know what you mean. 'Poorer' infrastructure excuse is void. If we cared about performance we'd get rid of almost all javascript, not https.
Yep. Also http2 more than makes up for the performance difference. And http2 requires TLS.
Off-topic, but the polite “disable your adblocker” message unobtrusively displayed at the end of the article is a nice way to do it. Lets me know I can support the site that way without hindering the reading experience.
Is the information being hidden intentionally to prevent attackers from gaining a toe-hold?
Well, Android has it always turned on for several years now.
Mobile applications require various permissions which can be enforced via SELinux.

SELinux policy can also be written to mitigate many vulnerabilities and vulnerability classes/vectors. Over 40% [1] of Android users may no longer be receiving important security updates, potentially putting them at risk of malware, data loss and cyber attacks.

Seems to make sense to have it enabled on Android based on the above.

[1] https://www.which.co.uk/news/2020/03/more-than-one-billion-a...

> Mobile applications require various permissions which can be enforced via SELinux.

What do you mean by this? SELinux can only deny things that would otherwise be allowed; it can never allow required permissions that would otherwise be denied.

Android's systems are developed alongside those policies, though. Things like lighttpd don't ship selinux policies, and bolting it on later is fragile.
Like others here, I had a similar experience. I setup a simple minecraft server on a SELinux secured OS. So far, so good. I wanted to setup a systemd service to startup and shutdown the minecraft server.

After ~1 hour of work later, I came to the conclusion that I was going to disable SELinux. Another hour later, I disabled SELinux.

Much as the article mentions, there didn't seem to be much good help, especially w.r.t. learning what the incantations meant and how to use them properly outside of a narrow path. Similarly, I did not have any decent way of introspecting what was going on in there. The error messages were of the "you must google this to even have a remote chance of figuring out what it means at all."

I understand SELinux is probably designed for enterprise or organizational specialists and not for normies to touch. It just seemed a bit too extreme towards that end.

Or designed to sell those services to you.
You hit the main issue with selinux: most documentation is aimed at policy developers and not end users. Your main issue was that you were trying to adapt the reference policy without knowing its inner workings.
Apparmor is -much- easier to write policies for; even more so if you use one of the ubuntu based distros that have decent rules already set up for most apps you'd use.
Hey, a few years ago, but after the 1.0 release, even the Kubernetes docs mentioned to turn SELinux off.

It’s just that SELinux documentation (something like a cookbook) is (or was) very hard to find on the internet.

I was in a similar situation. It always takes me way to long to find out that SELinux is responsible for a seemingly impossible to understand error behavior, until I give up, ask a colleague, he mentions SELinux and then it's suddenly obvious. So my conclusion is that the fail-behaviour is just not good. I would prefer my process to be killed with a nice clear error message somewhere. I think it all about giving the user the right information instead of failing silently.
I've always preferred apparmor. SELinux has always seemed radically more complex for very little benefit, unless you have a tightly constrained OS (like Android, where the VM does most of the work and every app has the same sort of security policy) or a team of admins working full time to maintain it (again, like Android).

Apparmor is weak in all the same ways SELinux is weak, at least in terms of the ways that actually matter - that is to say, a kernel exploit is the simplest way out of either. But anyone can write an apparmor profile for any program in an hour, and if you actually know wtf you're doing you can build very strong profiles and trivially test and maintain them.

SELinux is "good" in that if you are building a system like Android, great, consumers get very tight policies for free, and SELinux is ultimately more expressive. But I think 99% of companies looking at an LSM MAC should probably roll apparmor.

This is exactly my experience.

To expand a little, for a vertically integrated OS like Android or RHEL (official packages only!) SELinux can work.

For a sysadmin trying to configure a custom service or anything outside official repositories then AppArmor is actually usable where SELinux isn't.

But what you probably want is a Docker (or Podman) container, which gets you 90% of the hardening with 1% of the effort.

If a container isn't viable for whatever reason, then a systemd "contained" service is also very easy to configure. See `man systemd.exec`.

I think my main problems with AppArmor are the feature set isn't coherent across all distros that use it and it isn't integrated too well with audit tools. OpenSUSE ships distro patches that are a major hack to make ausearch properly show AA denials, while others need to look at dmesg and remember to disable printk ratelimit. The supported feature set is fun, the kernel mainline vs Ubuntu vs SUSE feature sets differ a lot. Ubuntu supports fine grained socket mediation (as in specific ops) & dbus. OpenSUSE supports some of the socket mediation, but as life has demonstrated some rules that work on Ubuntu are incorrectly downgraded and for instance all unix socket access gets blocked (though thanks to the AppArmor folks this got fixed now). Arch which I'm considering to be close to mainline has no dbus and no fine socket mediation. In theory one can use the same policy file on all systems, but the way it gets downgraded is not always predictable. At least the features are somewhat discoverable though /sys/kernel/security/apparmor tree, but I don't know what happens when say the kernel reports dbus mediation, but dbus-daemon was built without it. Then there are also some missing features, I think the abstract socket mediation is still not there. Lastly, the parser is super slow and memory hungry, especially when throwing some AARE heavy profiles at it. It happens that Ubuntu Core makes heavy use of apparmor profiles to lock down snaps on embedded Linux devices, and all the timings data that we collect show calling out to apparmor parser taking the largest chunk of the snap installation time.

FWIW mediation of dbus & network is already supported by SELinux in all implementations I've tried, but then SELinux has a separate set of warts. Eg. trying to use the same source policy and building it on hosts with different tooling/refpolicy. Using `optional_policy` doesn't cut it if types are not known at all, and as debugged with good folks from #selinux, the only way to work around this was using `ifndef` and passing defines to m4 interpreter.

IMHO most RedHat systems tend to be overengineered. Even the config file split is overengineered in RedHat compared to many other distros. And documentation, although existing, tends not to be detailed enough to understand how to deal with the systems. You need trial and error.
Well, unnecessary complexity full of YAGNI is exactly what the E in RHEL stands for. Red Hat products need to be complex enough so that somebody will pay for support. :)
The advice is poor and shows the authors lack of basic ability to understand basic selinux tooling.

It's doubly bad because most people running modern Linux run their apps in containers and don't need to understand it as they don't run into problems.

I'd this really is what gets the pageviews maybe someone should write a how-to on disabling all permissions because it's too hard.

Should I agree with the hivemind like this ?

Oh, What I meant to say is. The author is correct, selinux is too hard. I too am incompetent and unable to understand the many examples that demonstrate solving selinux issues.

What we really need is a shittier solution that lets good programs work while stopping bad people from doing bad things by using psychic powers and having a deep understanding of software that is yet to be written.

Author is correct that SELinux is not trivial and takes work to figure out.

Author is full of it in that they're obviously not aware of the tooling and information available. Eg:

All of this is wrong:

> Fedora Linux. There’s nowhere on the system where you can view the policies and look up why something might or might not work.

You can install the policy's source and look at it all you want. There are also tools to examine the current policy.

> The SELinux denial audit log messages are too vague. You’re told that a label was denied reading from another label. Okay, what do those labels mean? Which programs? Which files, sockets, or whatever?

You get that in the logs. What you get is an inode number, which isn't very user friendly, but it's very much there. SELinux has tooling to turn the log messages into something nicer to work with.

> So, you run the audit2allow command as instructed, and end up with some policy blob files.

> God only knows what changes the blobs do; you can’t be expected to, nor are you given enough information to evaluate them.

This is also wrong, along with the blob you get a text file.

TL;DR: The author has a minimal point, but clearly hasn't read the docs. Help and tooling is available and not that obscure.

Or, you could use setroubleshoot to learn it, and manage a linux machine properly.

But that's hard work.

Guess it's another SELINUX=disabled

After using CentOS for years, I have come to establish a debugging rule: If things just don't make sense, check if you're fighting SELinux policy. It's just one of those things that you beat your head on the desk after crashing into multiple brick walls that eventually works its way into your debugging process.

I guess it just shows how effective SELinux is if it is preventing the admin from doing something. /s

Sysadmin Rule #1 - Is it SELinux?

Sysadmin Rule #2 - Is it systemd?

Sysadmin Rule #3 - Have you checked the logs?

Where's the time where you could just assume it was DNS.
And Time..ntp etc.... ;)
That's covered by rule #2 (systemd-timedated)

;)

That's covered by rule #2 (systemd-resolved)
SELinux has a horrible misfeature called dontaudit, that lets policies using it deny actions without any evidence being logged anywhere. Because of the existence of this, the only reliable way to know if a problem is being caused by SELinux is to temporarily disable it and see if the problem goes away.
After years of setting permissive on my personal machine I wanted to do the right thing and set it up properly. I watched the presentations and all seemed so reasonable. It's there to help you, audit2allow will help you out even further if you need to allow something. Look at how detailed those error messages are explaining the problem and the solutions.

I thought I was going crazy that things weren't working and there were no denials in the log. After much pulling of hair I finally found out about dontaudit, I felt so cheated, it wasn't even playing fair at that point.

For anyone else hitting this, you can use semodule to disable dontaudit in step 4 [1]

[1] https://access.redhat.com/documentation/en-us/red_hat_enterp...

Not only that, but the official policies rely on dontaudit rules because there are known policy violations that are in fact harmless (like processes scanning entire directories, or attempting to open a file in various locations). So disabling dontaudit means your logs will get cluttered with non-related error messages that were up to then silently ignored.
SELinux really isn't that hard, especially if you spend a very short time to understand the basic concepts and commands.

SELinux for mere mortals: https://youtu.be/MxjenQ31b70

The gist of the problems is that the policies are not transparent (probably due to security reasons?) to the user/admin, did I get that right? And that there's a difference in enforcement between user policies and policies provided by the distribution?

All this sounds to me like a good idea that got lost in the implementation.

If you have no way to look up which policies are in effect and what is labeled and how, something that even Windows 10 gets right, then yeah. SELinux is a toxic mess.

> policies are not transparent (probably due to security reasons?)

Maybe, but also it just seems like the SELinux developers prefer a byzantine system.

Which is complete bullshit, the blog writer is just uninformed.

There are tools to examine the policy, and you can get the source to the entire thing. Though it's rather big and complex, but it's certainly there.

> The gist of the problems is that the policies are not transparent

Yes.

> (probably due to security reasons?) to the user/admin, did I get that right?

No, that isn’t the reason. They’re open source. The policies are, simply put, compiled binary blobs from a comprehensive set of allow-rules and label-path definitions. The complexity of analyzing and difficulty in overriding these complex rulesets is the problem. There are tools for interacting with the system, but good luck figuring out what they’re even called. All the tools are optimized for the ruleset developers and not the sysadmins that have to play by the rules (and are never told what the rules are).

Answering the question, “What do I need to label files that should be read by program X?” is waaay to hard. You’re expected to put your files in certain locations and then some things work out-of-the-box. However, there’s no documentation on where you’re supposed to put the files.

Sure, /var/www is where you put your website files by convention. Apache can read from that directory. But what if you put it in /var/web? You can relabel the directory, but it’s not at all apperent why everything grinds to a halt when you do. The /var/www dir is owned and readable by the apache user, but Apache still says complains it can’t read it. That’s the SELinux MAC in action blocking you from doing something totally normal just because you didn’t follow the strict rulesets (that no one told you about).

> There are tools for interacting with the system, but good luck figuring out what they’re even called.

They are mentionned in the selinux documentation of your distro.

> Answering the question, “What do I need to label files that should be read by program X?” is waaay to hard. You’re expected to put your files in certain locations and then some things work out-of-the-box. However, there’s no documentation on where you’re supposed to put the files.

The default directories are usually mentionned in the manuals of those programs. If you are using an selinux based distro, you know that if you don't use those default dirs you will have to label your custom dir. This is not hard to understand nor to do.

They make it so that you usually don't have too. You run into selinux issues usually only when you: - run some server stuff - try to serve a non default directory

And 99.99% of the time you will usually understand the issue from the log file and just label the correct files/directories. All this without having to change a policy. Policy creation/modification is pretty much the job of a package maintainer only.

I have been using Fedora daily for something like 7 years and have never had to write/modify a policy. The article originally linked is about some guy who do tests and run beta distros on prod and fiddle with his system by blindly copy/pasting stuff he sees in forums without really trying to understand what he does, then complain about his distro breaking on update. I don't think you can ever render your distro unbootable unless you do some very stupid things. And Fedora do not steer you to do those stupid things.

There are just so many policies it is not practical to list them all if you don't need them.

Only complain I would say is that sealert is not installed by default so if you want to have desktop notifications about an selinux issue you need to install it manually. I'd prefer it to be just a toggle in settings defaulting to no to decide to show or not show those notifications.

Longtime SA, constantly ribbed or outright insulted for my absolute hatred of SELinux. Yes, I just turn it off first thing. Well, used to when stuck with RHEL environments.

If you want people to adopt and really use something at large, you need to make it simple, explain when and why it's useful, and document it well. SELinux doesn't do any of that particularly well.

And now that most things are effectively running on a vm inside a vm, the use case seems dwindling even further.

I for one will not miss it.

Security can't be made simple. At the core what SELinux does is simply enforcing a policy. A list of "Should X do Y to Z?".

This is something that can't be implemented with just file permissions. What SELinux does is sandboxing every process it controls.

For instance, my cupsd is running as root. It's accepting connections on port 631.

If it started accepting connections on port 22, that's probably a bad thing. If it started messing around with /etc/passwd and /etc/shadow, that's probably not good either. It probably also has no business with my GPG keys, or /dev/sda.

But under the Unix permission model, if it runs as root, there's nothing you can do about it. It's root, it gets the entire system. If it has a hole, that's that.

SELinux first applies labels to stuff, then defines what actions can be done on what. So under SELinux there's a rule that says "A process with the label "cupsd_t can listen on a port labeled ipp_port_t". That's what lets it listen there, and absent a rule that allows it to listen on the ssh port, it's denied even if running as root.

So with a well implemented policy, if somebody exploits your cupsd, they can waste your paper. But despite it running as root they can't run a shell, can't open ports, can't mess with your password database, and can't install its own kernel driver. With the right rules, the attacker can find themselves at a dead end, where there's nothing useful they can do.

You can to some extent do this kind of thing with containers, but it really amounts to doing the same kind of work in the end to a large extent. If your container's security is at all useful you'll have to tell the system what should the cupsd container be able to do, in a very precise manner, and not just "eh, it can have root access to everything". At that point you've got another SELinux-like system to deal with.

Appreciate the detailed and thoughtful response.

That said, it seems like the more basic use cases can be accomplished more simply. For example, using capabilities and proper groups instead of running things as root has been the recommendation for a while now. In that scenario, cupsd would never be able to do much to the system if compromised in the first place.

A proper iptables/nftables default deny all incoming is pretty simple to setup, perhaps less so to maintain as services are added. I find the separation of concerns and maintenance a lot easier to reason about, ymmv.

How can I trust some opaque policy I cannot see? Not just trust that it is well intentioned not evil, (Oracle Linux?), but that it does what it says. And does what I need and that the opaque developers have correctly envisioned what I need to do.

Security by obscurity is worse than none at all. Security by buying an "Enterprise" product is worse than that.

What SELinux says is "real MAC security is super complicated, but don't worry we've taken care of all that for you, but you can't understand it or change anything". What I say is "easy peasy; if you access the machine you're root. Make sure that either it doesn't happen or it doesn't matter".

> but you can't understand it or change anything"

That is not true. SELinux is not hard to understand nor change. Most of the issues you might encounter are simply solved by changing a label in a file or directory. It is just not straightforward to debug and understand if you don't know it is there. I think most people who complain about it are multi distros/OS users and just only realize after losing precious time that an issue is selinux related.

But what am I, as the sysadmin, supposed to label things? Even if I know that I probably need to apply some labels, how do I find out what the policies are? What labels can interact with this program? You can turn to Google and find some incantations in a blog or forum post from ten years ago, but you can‘t easily see which labels a program is allowed to interact with or not. (If you even know to ask that question.)
Fedora comes with manpages. So for instance, say you want to place http pages outside of /var/www. Fedora comes with the selinux-policy-doc package, which gives you the httpd_selinux manpage:

https://linux.die.net/man/8/httpd_selinux

It's a tad dense, but in the Sharing Files you can find a section explaining what context is used and for what. You can also look at the existing context, eg:

    $ ls -laZ /var/www
    total 4
    drwxr-xr-x.  4 root root system_u:object_r:httpd_sys_content_t:s0       33 mar 17 17:32 .
    drwxr-xr-x. 21 root root system_u:object_r:var_t:s0                   4096 abr 18 10:57 ..
    drwxr-xr-x.  2 root root system_u:object_r:httpd_sys_script_exec_t:s0    6 mar 17 17:32 cgi-bin
    drwxr-xr-x.  2 root root system_u:object_r:httpd_sys_content_t:s0        6 mar 17 17:32 html
And copy those for your own use.
sesearch -A

That shows the list of what labels are allowed to do what to which labels, so run ps -Z to get the label of your process and grep the sesearch output for it, and that will tell you what labels it's allowed to interact with and in what ways.

selinux is generally pretty straightforward, but it has a reputation for being impenetrable which puts people of trying to learn it.

really? I don't mean understand how to apply a new label. I mean understand what the policies are and how they work, be able to create new ones that apply to you, and verify that the ones given to you by the distro are correct for your use. You're saying this is not hard to understand: https://github.com/SELinuxProject/refpolicy/blob/master/poli... ?

Otherwise you are blindly applying some black box.

My advice is to ALWAYS turn it off. As soon as you install a new system, turn it off (together with systemd).
> turn it off (together with systemd)

How practical is just turning off systemd today? I hate it too, but hasn't Red Hat basically strong-armed so many important Linux components into adding a hard-dep on it that your only way of avoiding it is to use a distro purpose-built to (e.g., Devuan)?

Systemd is only really required if you want to run gnome or kde easily. It's not an issue otherwise. Probably more trouble than it's worth to replace it in a distro that uses it by default though!
I don't think as a user you actually can remove systemd at all. Everything is set up to work with it. Removing systemd would be closer to forking the distro and maintaining it yourself. If you wanted to avoid systemd you would have to pick a distro which doesn't use it.
>As soon as you install a new system, turn it off

good advice

> together with systemd

lol why

It's a terrible advice, i really hope he's not a system admin.
I run thousands of severs. None of them have SELinux or systemd. It’s banned tech.
Well that just says nothing, it's not a sign for security or quality nor against it.

I run around 600 jails (so obviously no systemd (FreeBSD)), but the host for sure has pretty tight MAC policies (and some jails too).

What other MAC-System do you use? tomoyo? apparmor?

I have to complement your choice of FreeBSD and jails. If I didn’t have a Linux stack, I’d run FreeBSD and jails, too.

I wrote my own kernel modules that do exactly what I need in my stack and use case. No need for complicated SELinux, AppArmor or other solutions. I always roll my own solutions from the ground up (usually in a couple of all-nighters).

I needed around 5 years to slowly move away from Linux, open/-solaris/omnios/smartos was also in my mind, but...well you probably know the sad story behind it.

But FreeBSD really kicks, from firewall to database all the way down, everything FreeBSD ;)

Yes, I know the story. But what about Illumos?
>Illumos

Well illumos is just the kernel and userland (bit like BSD without ports/packets), Omnios is a really clean "server-distribution" with illumos at it's core but well same problem, not enough eye's and hand's (aka packets, documentation etc). I decided, that FreeBSD is the "more worry-free" solution for me...and still happy.

Because we didn’t ask for systemd. We like init scripts that we actually understand.
systemd isn't difficult to understand.
10 years into it and I still have no idea how to use it.
Operating system security was important back before VMs became cheap. At this point you are really wasting time if you invest significant effort in host security. It's the new network security.

Separate concerns into VMs and network connections separated by strong authentication, authorization and encryption, and practice least privilege. It doesn't matter if your OS or containers are made of security swiss cheese as long as compromising one thing doesn't lead to compromising another. For containers you need Firecracker VMs; there is no other strong isolation for Linux containers, everything else is pretty easy to pop.

>It doesn't matter if your OS or containers are made of security swiss cheese as long as compromising one thing doesn't lead to compromising another.

I hope you never work with customer related data.

I’ve heard several high-level security engineers take this stance in organizations with stringent security requirements. There may be some truth here when prioritizing work, but I have yet to see strong authn/authz prevent red teams from wrecking havoc.

It’s too complex. We like to think of systems as being fairly constrained, but in practice I am not convinced that is true. Once you start adding other business functions to your environment, like observability, you can introduce non-obvious gaps in your policies.

Would having OS security completely prevent an attacker from wrecking havoc? Probably not. But it would make it much more difficult. It can also protect you from container/VM escapes.

Are SELinux policies complex? Yes, but they are constrained to a host’s system and are yet another layer of defense that can be used to secure software.

I’ve seen again and again how an SELinux policy can prevent an exploit from causing harm. It can also be an effective and quick way to mitigate risks from a new 0-day being posted while software teams work on patching.

I am fairly convinced, or bullish, that making SELinux easier to configure is a solvable problem. The biggest hurdle to it is this puzzling movement within security to avoid OS-level controls and instead focus on network-level controls. It puzzles me why a well-resourced org thinks you can only invest in one or the other.

I have to say, for sysadmin work I find this view sorta overblown.

My experience is with RHEL and derivatives, not Fedora, and for the most part those are very straightforward and while selling does rear it's head every once in a while, it's usually not that problematic to work around.

When you have something failing that you need to fix and isn't an upstream problem (i.e. your own app or some third party vendor), you set the system to permissive mode and let it run with the app long enough that you think you've hit all the use cases, and then you use ausearch and audit2allow to generate a module for it. And bi, while the selinux audit log entries (which ausearch shows) aren't super clear, you can learn to interpret the gist of them, and piping them to audit2why and audit2allow gives more context.

The real "trick" in the above is to make sure you run the system in permissive mode for a while. Otherwise you'll usually only see the first deny in a code path which the app will then fail on, and you won't see subsequent ones. Permissive mode means nothing is actually denied, but all thing that would be denials are logged as such.

For things that ship with the OS repos for RHEL and derivatives, my experience is that very rarely are there problems or things that are not obvious to fix (running errors through audit2why will tell you when there's a boolean to toggle to allow what you want, such as outbound tcp connections from the http context that is causing some PHP app to malfunction).

You can also write a stub policy which is permissive for all actions, with logging turned on. This means you can run just the one application in permissive mode, get a sense of its behavior, and then lock it down.
> and then you use ausearch and audit2allow to generate a module for it. And bi, while the selinux audit log entries (which ausearch shows) aren't super clear,

That still sounds pretty complicated for most people. I mean, I know a lot of otherwise capable people who think NoScript is too much to manage and that's something I've heard repeated online many times. That's just clicks, and only when you actually need to allow something. I would think that if even the people who own websites where they write entire articles about linux find something over-complicated and poorly documented most computer users wont stand a chance.

I agree, which is why I prefaced all that with "for sysadmin work", which I think has a different standard than for regular people.
Sysadmins are just regular people with more experience. Sometimes, regular people even become sysadmins! ;)
This is a common misconception. No normal person ever becomes a sysadmin. In the cases where you think that has happened, they invariably fly their freak flag high soon after. ;)
(comment deleted)
In my experience creating and applying new policies with audit2allow is almost always the wrong thing to do. Most SELinux issues are either a SELinux boolean that needs enabling, or SELinux file type that needs changing.

The few times where you do need to create new policies then audit2allow is useful but still requires you to review and understand the changes it's going to make before applying them.

Exactly this. I’ve run SELinux on for various workloads for over a decade and have barely ever had to touch audit2allow. And what I have done is codified in ansible so you can just copy and adjust for new cases.
> In my experience creating and applying new policies with audit2allow is almost always the wrong thing to do. Most SELinux issues are either a SELinux boolean that needs enabling, or SELinux file type that needs changing.

I think that's very dependent on what you're doing, and how supported the thing your doing is by the OS. We write a lot of custom software. We also end up installing a lot of applications that didn't ship with good (or any) rulesets, or that we packaged into RPMs ourselves. Using audit2allow (after first checking audit2why and booleans) has become standard enough in those cases to generate a ruleset that makes sense (either for immediate installation or adding to a package we're building) that my experience seems to be somewhat different than yours. Or maybe we just run a lot more servers and while the percentages are the same the total numbers look higher, I don't know.

There's also the cases where we basically threw our hands up and said screw it, run in permissive mode indefinitely, because the alternative it too annoying and error prone (I'm looking at you, Jira).

> The few times where you do need to create new policies then audit2allow is useful but still requires you to review and understand the changes it's going to make before applying them.

Yep, and I noted that I don't think the audit logs and autdit2allow output aren't actually all that hard to understand if you take the time to look.

The three paragraphs starting with "In the best-case scenario" address exactly what you're talking about. And in my brief (hobbyist) usage of CentOS 7 with trying to run some self-written software, what TFA says was exactly my experience.

As it turned out, the hardening provided by systemd (private tmp, restricted syscalls, etc) was sufficient, and easier to understand, for my use case.

Sure, but it also sounds like your usage isn't really sysadmin level, which is what I prefaced everything I said with to put it into that context.

I don't expect random users to run with selinux on and deal with problems for all the stuff they might do. I do think it's probably a good idea for system administrators, and if those sysadmins have problems getting some custom in-house software running through selinux, that seems like a good place for them to focus some learning to rectify that issue.

Honestly I thought this was going to be about the problems of fully utilizing SELinux. There are bits of SELinux which are just missing - like a shared network policy server, or the various concepts of transiting SELinux contexts across things like network links to provide network-wide security.

SELinux is one of those things that makes total sense to me, but the implementation just leaves so much to be desired - i.e. basically no practical usages of "users" in an SELinux context even though the concept is there.

The reason I always had SELinux turned off: I would either run Ubuntu, Arch, of Amazon Linux.

The Ubuntu story is not great, and you can see you're swimming against the tide of common deployments: https://wiki.ubuntu.com/SELinux

Arch doesn't ship with the tooling in the distro itself: https://wiki.archlinux.org/title/SELinux

And Amazon has just released "Amazon Linux 2" which includes "now supports SELinux as a feature".

Next version of Amazon Linux (2022) will have SELinux enabled by default.
How does SElinux compare to Secure Boot / SIP?
Security-Enhanced Linux (SELinux) is a security architecture for Linux systems that allows administrators to have more control over who can access the system. It was originally developed by the NSA.

Secure Boot and SIP are about boot integrity preventing malware early on in the boot process [1]

[1] https://www.rodsbooks.com/refind/secureboot.html

SELinux and Secure Boot are largely orthogonal. Secure Boot can be used to establish a chain of trust to guarantee that you are running software that is not tampered (using asymmetric cryptography). For example, Secure Boot can verify that the bootloader is an unmodified blob from a trusted vendor. In turn, the bootloader can verify the kernel. The kernel can verify modules/extensions. In principle, you could extend this chain to ordinary programs.

You can use SELinux without Secure Boot and Secure Boot without SELinux. Secure Boot can make SELinux more effective, because you can use it to verify that the kernel is not tampered with, so you know that it is properly enforcing the SELinux policies. You could also verify cryptographically whether a policy is not tampered with, but I am not sure if that is currently supported.

The comparison between SELinux and SIP is a bit more complicated. SELinux is a security framework that allows you to write all kinds of policies, whereas SIP is a very specific set of defenses.

On of the main features of SIP is that it makes certain system paths unwritable for every process that doesn't have the right entitlements, including processes with PID 0 (root), unless they have the the necessary entitlements [1]. Since SELinux is a generic security framework, you can implement something similar to SIP's path protection using SELinux. For example, system paths could be labeled with a special label and writes can be restricted to processes with a particular SELinux context. More concretely, you could use SELinux to forbid that any process, including root processes, can write to a system path like /usr/bin. Then you could allow the security context in which DNF/RPM (the Fedora package manager) run to modify system paths like /usr/bin [2].

[1] SIP does more stuff, like disallowing unsigned kernel extensions, preventing code injection, etc.

[2] Russell Coker has set up an SSH machine for which he gives away the root password. But you can't do much with it, because the SELinux policy prevents you: https://www.coker.com.au/selinux/play.html