Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/biboumi: init #94917

Merged
merged 1 commit into from
Sep 2, 2020
Merged

nixos/biboumi: init #94917

merged 1 commit into from
Sep 2, 2020

Conversation

ju1m
Copy link
Contributor

@ju1m ju1m commented Aug 8, 2020

Motivation for this change

To use Biboumi, an XMPP to IRC gateway: https://biboumi.louiz.org/

Things done
  • Update biboumi to its latest release: 8.5
  • Add services.biboumi
  • Make systemd-analyze security biboumi return OK
  • Leveraging freeformType on services.biboumi.settings.
  NAME                                                        DESCRIPTION                                                                   EXPOSURE
✗ PrivateNetwork=                                             Service has access to the host's network                                           0.5
✓ User=/DynamicUser=                                          Service runs under a transient non-root user identity                                 
✓ CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)                Service cannot change UID/GID identities/capabilities                                 
✓ CapabilityBoundingSet=~CAP_SYS_ADMIN                        Service has no administrator privileges                                               
✓ CapabilityBoundingSet=~CAP_SYS_PTRACE                       Service has no ptrace() debugging abilities                                           
✗ RestrictAddressFamilies=~AF_(INET|INET6)                    Service may allocate Internet sockets                                              0.3
✓ RestrictNamespaces=~CLONE_NEWUSER                           Service cannot create user namespaces                                                 
✓ RestrictAddressFamilies=~…                                  Service cannot allocate exotic sockets                                                
✓ CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP)           Service cannot change file ownership/access mode/capabilities                         
✓ CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER)         Service cannot override UNIX file/IPC permission checks                               
✓ CapabilityBoundingSet=~CAP_NET_ADMIN                        Service has no network configuration privileges                                       
✓ CapabilityBoundingSet=~CAP_RAWIO                            Service has no raw I/O access                                                         
✓ CapabilityBoundingSet=~CAP_SYS_MODULE                       Service cannot load kernel modules                                                    
✓ CapabilityBoundingSet=~CAP_SYS_TIME                         Service processes cannot change the system clock                                      
✗ DeviceAllow=                                                Service has a device ACL with some special devices                                 0.1
✗ IPAddressDeny=                                              Service does not define an IP address whitelist                                    0.2
✓ KeyringMode=                                                Service doesn't share key material with other services                                
✓ NoNewPrivileges=                                            Service processes cannot acquire new privileges                                       
✓ NotifyAccess=                                               Service child processes cannot alter service state                                    
✓ PrivateDevices=                                             Service has no access to hardware devices                                             
✓ PrivateMounts=                                              Service cannot install system mounts                                                  
✓ PrivateTmp=                                                 Service has no access to other software's temporary files                             
✗ PrivateUsers=                                               Service has access to other users                                                  0.2
✓ ProtectClock=                                               Service cannot write to the hardware clock or system clock                            
✓ ProtectControlGroups=                                       Service cannot modify the control group file system                                   
✓ ProtectHome=                                                Service has no access to home directories                                             
✓ ProtectKernelLogs=                                          Service cannot read from or write to the kernel log ring buffer                       
✓ ProtectKernelModules=                                       Service cannot load or read kernel modules                                            
✓ ProtectKernelTunables=                                      Service cannot alter kernel tunables (/proc/sys, …)                                   
✓ ProtectSystem=                                              Service has strict read-only access to the OS file hierarchy                          
✓ RestrictAddressFamilies=~AF_PACKET                          Service cannot allocate packet sockets                                                
✓ RestrictSUIDSGID=                                           SUID/SGID file creation by service is restricted                                      
✓ SystemCallArchitectures=                                    Service may execute system calls only with native ABI                                 
✓ SystemCallFilter=~@clock                                    System call whitelist defined for service, and @clock is not included                 
✓ SystemCallFilter=~@debug                                    System call whitelist defined for service, and @debug is not included                 
✓ SystemCallFilter=~@module                                   System call whitelist defined for service, and @module is not included                
✓ SystemCallFilter=~@mount                                    System call whitelist defined for service, and @mount is not included                 
✓ SystemCallFilter=~@raw-io                                   System call whitelist defined for service, and @raw-io is not included                
✓ SystemCallFilter=~@reboot                                   System call whitelist defined for service, and @reboot is not included                
✓ SystemCallFilter=~@swap                                     System call whitelist defined for service, and @swap is not included                  
✗ SystemCallFilter=~@privileged                               System call whitelist defined for service, and @privileged is included             0.2
✓ SystemCallFilter=~@resources                                System call whitelist defined for service, and @resources is not included             
✗ AmbientCapabilities=                                        Service process receives ambient capabilities                                      0.1
✓ CapabilityBoundingSet=~CAP_AUDIT_*                          Service has no audit subsystem access                                                 
✓ CapabilityBoundingSet=~CAP_KILL                             Service cannot send UNIX signals to arbitrary processes                               
✓ CapabilityBoundingSet=~CAP_MKNOD                            Service cannot create device nodes                                                    
✗ CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW) Service has elevated networking privileges                                         0.1
✓ CapabilityBoundingSet=~CAP_SYSLOG                           Service has no access to kernel logging                                               
✓ CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE)              Service has no privileges to change resource use parameters                           
✓ RestrictNamespaces=~CLONE_NEWCGROUP                         Service cannot create cgroup namespaces                                               
✓ RestrictNamespaces=~CLONE_NEWIPC                            Service cannot create IPC namespaces                                                  
✓ RestrictNamespaces=~CLONE_NEWNET                            Service cannot create network namespaces                                              
✓ RestrictNamespaces=~CLONE_NEWNS                             Service cannot create file system namespaces                                          
✓ RestrictNamespaces=~CLONE_NEWPID                            Service cannot create process namespaces                                              
✓ RestrictRealtime=                                           Service realtime scheduling access is restricted                                      
✓ SystemCallFilter=~@cpu-emulation                            System call whitelist defined for service, and @cpu-emulation is not included         
✓ SystemCallFilter=~@obsolete                                 System call whitelist defined for service, and @obsolete is not included              
✓ RestrictAddressFamilies=~AF_NETLINK                         Service cannot allocate netlink sockets                                               
✓ RootDirectory=/RootImage=                                   Service has its own root directory/image                                              
✓ SupplementaryGroups=                                        Service has no supplementary groups                                                   
✓ CapabilityBoundingSet=~CAP_MAC_*                            Service cannot adjust SMACK MAC                                                       
✓ CapabilityBoundingSet=~CAP_SYS_BOOT                         Service cannot issue reboot()                                                         
✓ Delegate=                                                   Service does not maintain its own delegated control group subtree                     
✓ LockPersonality=                                            Service cannot change ABI personality                                                 
✓ MemoryDenyWriteExecute=                                     Service cannot create writable executable memory mappings                             
✓ RemoveIPC=                                                  Service user cannot leave SysV IPC objects around                                     
✓ RestrictNamespaces=~CLONE_NEWUTS                            Service cannot create hostname namespaces                                             
✓ UMask=                                                      Files created by service are accessible only by service's own user by default         
✓ CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE                  Service cannot mark files immutable                                                   
✓ CapabilityBoundingSet=~CAP_IPC_LOCK                         Service cannot lock memory into RAM                                                   
✓ CapabilityBoundingSet=~CAP_SYS_CHROOT                       Service cannot issue chroot()                                                         
✓ ProtectHostname=                                            Service cannot change system host/domainname                                          
✓ CapabilityBoundingSet=~CAP_BLOCK_SUSPEND                    Service cannot establish wake locks                                                   
✓ CapabilityBoundingSet=~CAP_LEASE                            Service cannot create file leases                                                     
✓ CapabilityBoundingSet=~CAP_SYS_PACCT                        Service cannot use acct()                                                             
✓ CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG                   Service cannot issue vhangup()                                                        
✓ CapabilityBoundingSet=~CAP_WAKE_ALARM                       Service cannot program timers that wake up the system                                 
✗ RestrictAddressFamilies=~AF_UNIX                            Service may allocate local sockets                                                 0.1

→ Overall exposure level for biboumi.service: 1.5 OK 🙂

Note that ✗ PrivateUsers= is due to the need for AmbientCapabilities=CAP_NET_BIND_SERVICE (See https://bugs.archlinux.org/task/65921 ) . If Biboumi's upstream were to support a systemd's socket for the identd port, PrivateUsers=true would likely be doable.

  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

@ofborg ofborg bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Aug 8, 2020
@picnoir
Copy link
Member

picnoir commented Aug 8, 2020

Did you contacted upstream regarding the systemd hardening?

I just had a quick look to their repo, looks like they're providing several Dockerfile but no contrib systemd service. It could be nice to upstream this set of hardening options and see with upstream whether this is going to break any runtime assumption they have.

To be clear: this would be a nice to have but won't block this PR.

Reviewing a module not having any tests is always a bit tricky. Not having any tests will also make it harder for you to maintain the module on the long run. I do understand though that this module will require both a XMPP server and a IRC one to test...

Do you think you could leverage the prosody test and mock the IRC part?

@ju1m
Copy link
Contributor Author

ju1m commented Aug 8, 2020

@NinjaTrappeur

  • I've mentionned this PR to @louiz on xmpp:[email protected]?join
  • There is an upstream's biboumi.service generated through cmake in pkgs.biboumi, but it sets User=/Group= whereas this PR's uses DynamicUser=:
[Unit]
Description=Biboumi, XMPP to IRC gateway
Documentation=man:biboumi(1) https://biboumi.louiz.org
After=network.target

[Service]
Type=notify
ExecStart=/nix/store/dvg2nygqv8r73fzc7hiyin6zp6i9zl29-biboumi-8.5/bin/biboumi /etc/biboumi/biboumi.cfg
ExecReload=/bin/kill -s USR1 $MAINPID
WatchdogSec=20
Restart=always
User=nobody
Group=nobody

[Install]
WantedBy=multi-user.target
  • Concerning tests, it would be better indeed to have something, but writting and securing this module has already exhausted me enough for this round, so I'll pass for now :P
    However here's my config if that may help:
{ pkgs, lib, config, ... }:
let
  inherit (config) networking;
  inherit (config.services) biboumi;
  inherit (config.users) users;
in
{
services.prosody.extraConfig = ''
    Component "biboumi.${networking.domain}"
      component_secret = "useless-secret-on-loopback"
'';
services.prosody.disco_items = [
  { url = "biboumi.${networking.domain}";
    description = "Passerelle vers des serveurs IRC (Internet Relay Chat)"; }
];
networking.nftables.ruleset = ''
  add rule inet filter net2fw tcp dport ${toString biboumi.settings.identd_port} counter accept comment "identd"
  add rule inet filter fw2net meta skuid ${users.biboumi.name} meta l4proto tcp counter accept comment "Biboumi"
'';
users.users.biboumi.isSystemUser = true;
systemd.services.biboumi.after = ["prosody.service"];
services.biboumi = {
  enable = true;
  settings = {
    hostname = "biboumi.${networking.domain}";
    password = "useless-secret-on-loopback";
    xmpp_server_ip = "127.0.0.1";
    port = 5347;
    admin = lib.concatStringsSep ":" [
      "julm@${networking.domain}"
    ];
    #fixed_irc_server = "";
    persistent_by_default = true;
    realname_customization = true;
    realname_from_jid = false;
    log_level = 1;
  };
};
}

@louiz
Copy link

louiz commented Aug 10, 2020

Upstream here, just to notify that I noted the use of a systemd-socket for the 113 port here: https://lab.louiz.org/louiz/biboumi/-/issues/3441

I don’t know when this will be done, if at all. But at least it will not be forgotten.

Copy link
Member

@picnoir picnoir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your work on this module. I tested this on my infra and did not faced any issue so far. The systemd service is nicely hardened, kudos!

Thetypes.attrs-based configuration seems a bit loose to me. Having to deploy the whole configuration just to read you're missing a mandatory attribute in the service logs is a long and tedious process. I think we should leverage either the NixOS module system either the software itself to validate as much configuration as possible at build time.

It seems like biboumi lacks such a -t config test flag. It's a shame. I opened a PR upstream adding this: https://lab.louiz.org/louiz/biboumi/-/merge_requests/56. I think we can move forward with this PR without this static test though.

In the meantime, we probably could add either add some module options/assertions for the mandatory attributes (hostname, password).

Once that being done, I think we'll be ready to merge this.

@ju1m
Copy link
Contributor Author

ju1m commented Aug 31, 2020

@NinjaTrappeur Thanks for the review, I've moved the RFC0042 settings from types.attrs to freeformType.

@ju1m ju1m force-pushed the biboumi branch 4 times, most recently from 3fbeeda to dc10874 Compare August 31, 2020 23:30
@picnoir
Copy link
Member

picnoir commented Sep 1, 2020

I have a build failure around the hostname default value now, looks like we should either explicitely point to config.networking.domain, either inheriting config.networking here.

I'll have a deeper look to this tonight.

@ju1m
Copy link
Contributor Author

ju1m commented Sep 1, 2020

@NinjaTrappeur Fixed, thanks!

@picnoir
Copy link
Member

picnoir commented Sep 1, 2020

We're still having a problem.

The ofborg error is coming from the default hostname.

diff --git a/nixos/modules/services/networking/biboumi.nix b/nixos/modules/services/networking/biboumi.nix
index 0c90d46cabf..9d713ba1ebf 100644
--- a/nixos/modules/services/networking/biboumi.nix
+++ b/nixos/modules/services/networking/biboumi.nix
@@ -58,7 +58,6 @@ in
           };
           options.hostname = mkOption {
             type = types.str;
-            default = "biboumi.${config.networking.domain}";
             example = "biboumi.example.org";
             description = ''
               The hostname served by the XMPP gateway.

Fixes it.

I now have another strange doc-related error when deploying this on top of the current nixos-unstable, ie. c59ea8b8a0e7:

building Nix...
building the system configuration...
error: while evaluating the attribute 'activationScript' of the derivation 'nixos-system-seldon-20.09.git.73152f0e68eM' at nixpkgs/nixos/modules/system/activation/top-level.nix:95:5:
while evaluating the attribute 'system.activationScripts.script' at nixpkgs/nixos/modules/system/activation/activation-script.nix:68:9:
while evaluating 'textClosureMap' at nixpkgs/lib/strings-with-deps.nix:70:35, called from nixpkgs/nixos/modules/system/activation/activation-script.nix:89:18:
while evaluating 'id' at nixpkgs/lib/trivial.nix:14:5, called from undefined position:
while evaluating the attribute 'text' at nixpkgs/nixos/modules/system/activation/activation-script.nix:9:5:
while evaluating the attribute 'text' at nixpkgs/lib/strings-with-deps.nix:77:38:
while evaluating the attribute 'sources' of the derivation 'etc' at nixpkgs/nixos/modules/system/etc/etc.nix:12:5:
while evaluating anonymous function at nixpkgs/nixos/modules/system/etc/etc.nix:20:20, called from undefined position:
while evaluating the attribute 'source' at undefined position:
while evaluating 'g' at nixpkgs/lib/attrsets.nix:276:19, called from undefined position:
while evaluating anonymous function at nixpkgs/lib/modules.nix:98:72, called from nixpkgs/lib/attrsets.nix:279:20:
while evaluating the attribute 'value' at nixpkgs/lib/modules.nix:461:9:
while evaluating the option `environment.etc.dbus-1.source':
while evaluating the attribute 'mergedValue' at nixpkgs/lib/modules.nix:493:5:
while evaluating anonymous function at nixpkgs/lib/modules.nix:495:17, called from nixpkgs/lib/modules.nix:495:12:
while evaluating 'check' at nixpkgs/lib/types.nix:251:15, called from nixpkgs/lib/modules.nix:495:22:
while evaluating the attribute 'serviceDirectories' of the derivation 'dbus-1' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
while evaluating anonymous function at nixpkgs/lib/types.nix:263:14, called from undefined position:
while evaluating the attribute 'value' at nixpkgs/lib/modules.nix:506:27:
while evaluating anonymous function at nixpkgs/lib/modules.nix:495:17, called from nixpkgs/lib/modules.nix:495:12:
while evaluating 'check' at nixpkgs/lib/types.nix:251:15, called from nixpkgs/lib/modules.nix:495:22:
while evaluating the attribute 'passAsFile' of the derivation 'system-path' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
while evaluating the attribute 'buildCommand' of the derivation 'nixos-manpages' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
while evaluating the attribute 'buildCommand' of the derivation 'manual-olinkdb' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
while evaluating the attribute 'buildCommand' of the derivation 'nixos-manual-combined' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
while evaluating the attribute 'buildCommand' of the derivation 'generated-docbook' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
while evaluating the attribute 'buildCommand' of the derivation 'options-docbook.xml' at nixpkgs/pkgs/build-support/trivial-builders.nix:7:7:
in 'toFile': the file 'options.xml' cannot refer to derivation outputs, at nixpkgs/nixos/lib/make-options-doc/default.nix:89:16

I tried removing all the links & derivations mention in the options defaults & doc without any effect. This is the first time I'm working with freeformType, I guess the problem is somehow linked to that. I'll have a further look tomorrow night.

In the meantime, feel free to pull your hair as well on this one :P

@picnoir
Copy link
Member

picnoir commented Sep 1, 2020

Alright, I found the issue: it comes from the ca_file default.

NixOS's system ca bundle is pointing to /etc/ssl/certs/ca-certificates.crt. Pointing to this location is the best we can do for now. See #8247 for more context.

So overall, once we apply the following patch, we'll be good to go (manually tested on my personal infra).

diff --git a/nixos/modules/services/networking/biboumi.nix b/nixos/modules/services/networking/biboumi.nix
index 0c90d46cabf..ac37e03446f 100644
--- a/nixos/modules/services/networking/biboumi.nix
+++ b/nixos/modules/services/networking/biboumi.nix
@@ -42,7 +42,7 @@ in
           };
           options.ca_file = mkOption {
             type = types.path;
-            default = "" + etc."ssl/certs/ca-certificates.crt".source;
+            default = "/etc/ssl/certs/ca-certificates.crt";
             description = ''
               Specifies which file should be used as the list of trusted CA
               when negociating a TLS session.
@@ -58,7 +58,6 @@ in
           };
           options.hostname = mkOption {
             type = types.str;
-            default = "biboumi.${config.networking.domain}";
             example = "biboumi.example.org";
             description = ''
               The hostname served by the XMPP gateway.

We'll probably want to add some rudimentary testing in a subsequent PR. As we can see with these eval failures, there are a lot of moving parts here, it might turn into a pain to maintain.

@ju1m
Copy link
Contributor Author

ju1m commented Sep 1, 2020

@NinjaTrappeur Thanks again for the debugging and sorry for not having seen the problems earlier: I'm still a bit submerged and lost in ofborg's mails and WebUI, and the "This failed status will be cleared when ofborg finishes eval." mislead me into believing it would somehow succeed.

@picnoir
Copy link
Member

picnoir commented Sep 2, 2020

The CI is still red: we have a trailing space line 55. Everything should be green once this space gets removed.

Note: you probably want to configure your editor to remove those when saving a file.

(add-hook 'before-save-hook 'delete-trailing-whitespace)

on emacs.

@ju1m
Copy link
Contributor Author

ju1m commented Sep 2, 2020

@NinjaTrappeur Thanks again. And while we're at it, the following should do under vim:

fun! TrimWhitespace()
  let l:save = winsaveview()
  keeppatterns %s/\s\+$//e
  call winrestview(l:save)
endfun
autocmd BufWritePre *.nix :call TrimWhitespace()

Copy link
Member

@picnoir picnoir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@picnoir picnoir merged commit 09c383c into NixOS:master Sep 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 1-10 10.rebuild-darwin: 1 10.rebuild-linux: 1-10
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants