From 30615ddb5f06f802e327b9ac7c0651d4a24500a2 Mon Sep 17 00:00:00 2001
From: Julien Marquet
Date: Tue, 26 Jul 2022 15:06:42 +0200
Subject: [PATCH] More info about hardening
---
.envrc | 1 +
src/ServicesTable.elm | 21 ++++++++++++++-------
src/services-info.md | 24 ++++++++++++++++++++++++
src/{ => templates}/services-info.html | 5 ++++-
ssg/src/Main.hs | 12 +++++++-----
5 files changed, 50 insertions(+), 13 deletions(-)
create mode 100644 .envrc
create mode 100644 src/services-info.md
rename src/{ => templates}/services-info.html (97%)
diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..1d953f4
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use nix
diff --git a/src/ServicesTable.elm b/src/ServicesTable.elm
index fb9bb86..8dc2906 100644
--- a/src/ServicesTable.elm
+++ b/src/ServicesTable.elm
@@ -2,6 +2,7 @@
module ServicesTable exposing (main)
import List
+import String exposing (fromInt)
import Browser
import Html exposing (Html, div, span, text, table, thead, tbody, tr, th, td)
import Html.Attributes exposing (class)
@@ -38,7 +39,10 @@ init _ =
( Loading
, Http.get
{ url = "https://share.recursor.wf/systemd-services-tests.json"
- , expect = Http.expectJson GotInfo dataDecoder } )
+ , expect = Http.expectJson GotInfo (map sorted dataDecoder) } )
+
+sorted : Info -> Info
+sorted info = List.sortBy (\{name, fields, tests, mod} -> (List.length fields, name)) info
dataDecoder : Decoder Info
dataDecoder = map (List.map (\(name, (fields, tests, mod)) -> { name = name, fields = fields, tests = tests, mod = mod }))
@@ -81,19 +85,22 @@ view model = case model of
Loading -> text "Loading..."
Success info -> renderTable info
+rotated : String -> Html Msg
+rotated txt = th [ class "rotate-45" ] [ div [] [ span [] [ text txt ] ] ]
+
headers : Html Msg
headers = tr []
- <| [ th [] [ text "source" ], th [] [ text "module" ] ]
- ++ List.map (\name -> th [ class "rotate-45" ] [ div [] [ span [] [ text name ] ] ]) watchedFields
+ <| [ th [] [ text "source" ], th [] [ text "#" ], th [] [ text "module" ] ]
+ ++ List.map rotated watchedFields
renderTable : Info -> Html Msg
renderTable info = table [ class "services-table", class "table-header-rotated" ]
[ thead [ class "info-thead" ] [ headers ]
- , tbody [] (List.map renderLine info) ]
+ , tbody [] (List.indexedMap renderLine info) ]
-renderLine : { name : String, fields : List String, tests : List String, mod : String } -> Html Msg
-renderLine {name, fields, tests, mod} = tr []
- <| [ th [] [ text mod ], th [] [ text name ] ]
+renderLine : Int -> { name : String, fields : List String, tests : List String, mod : String } -> Html Msg
+renderLine i {name, fields, tests, mod} = tr []
+ <| [ th [] [ text mod ], th [] [ text <| fromInt i ], th [] [ text name ] ]
++ (List.map (\b -> td [class (if b then "cell-good" else "cell-bad")] [text (if b then "✓" else "✗")])
<| List.map (\field -> not <| List.member field fields) watchedFields)
diff --git a/src/services-info.md b/src/services-info.md
new file mode 100644
index 0000000..85c2dcd
--- /dev/null
+++ b/src/services-info.md
@@ -0,0 +1,24 @@
+---
+title: sandboxing audit -- NixOS services
+---
+This table shows, for each systemd service in nixos, the hardening options that are configured.
+The items are sorted by decreasing count of configured options, then by name.
+
+This is the current result of [a work-in-progress project](https://github.com/thejohncrafter/nixos-harden-systemd)
+with the support of the [nlnet foundation](https://nlnet.nl/).
+
+The goal of the project is to audit the security of every systemd service in
+[NixOS](https://nixos.org/). For the moment (*modulo* the power of my static analysis tool, that
+may miss some parts of nixpkgs), I built a list of all the systemd services that are defined in NixOS
+and I automatically read the configuration of these services with respect to systemd hardening.
+The entries in this table are green if the servie configures the option, and red otherwise.
+
+### Caveats
+
+ - For now, I only target a restricted list of options (boolean options that are "well-behaved").
+ - This shows the options that are *configured*, but not necessarily *secured*: for instance,
+ `transmission` configures `PrivateNetwork` and this options appears in green,
+ yet it is configured by default to `false`. This means there may be false positives.
+
+ There may also be some false negatives: for instance, nginx does not configure `PrivateNetwork`,
+ but this is expected because nginx has no reason to shut itself from the Internet.
diff --git a/src/services-info.html b/src/templates/services-info.html
similarity index 97%
rename from src/services-info.html
rename to src/templates/services-info.html
index d27c040..dedcb44 100644
--- a/src/services-info.html
+++ b/src/templates/services-info.html
@@ -2,9 +2,12 @@
- Packages info
+ $title$
+
+ $body$
+