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

Systemd journal remote and related #189277

Merged
merged 10 commits into from
Dec 10, 2023
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2405.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ In addition to numerous new and upgraded packages, this release has the followin

- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable).

- systemd's gateway, upload, and remote services, which provides ways of sending journals across the network. Enable using [services.journald.gateway](#opt-services.journald.gateway.enable), [services.journald.upload](#opt-services.journald.upload.enable), and [services.journald.remote](#opt-services.journald.remote.enable).

- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares.

Expand Down
3 changes: 3 additions & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,9 @@
./system/boot/systemd/initrd-secrets.nix
./system/boot/systemd/initrd.nix
./system/boot/systemd/journald.nix
./system/boot/systemd/journald-gateway.nix
./system/boot/systemd/journald-remote.nix
./system/boot/systemd/journald-upload.nix
./system/boot/systemd/logind.nix
./system/boot/systemd/nspawn.nix
./system/boot/systemd/oomd.nix
Expand Down
135 changes: 135 additions & 0 deletions nixos/modules/system/boot/systemd/journald-gateway.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{ config, lib, pkgs, ... }:

let
cfg = config.services.journald.gateway;

cliArgs = lib.cli.toGNUCommandLineShell { } {
# If either of these are null / false, they are not passed in the command-line
inherit (cfg) cert key trust system user merge;
};
in
{
meta.maintainers = [ lib.maintainers.raitobezarius ];
options.services.journald.gateway = {
enable = lib.mkEnableOption "the HTTP gateway to the journal";

port = lib.mkOption {
default = 19531;
type = lib.types.port;
description = ''
The port to listen to.
'';
};

cert = lib.mkOption {
default = null;
type = with lib.types; nullOr str;
description = lib.mdDoc ''
The path to a file or `AF_UNIX` stream socket to read the server
certificate from.

The certificate must be in PEM format. This option switches
`systemd-journal-gatewayd` into HTTPS mode and must be used together
with {option}`services.journald.gateway.key`.
'';
};

key = lib.mkOption {
default = null;
type = with lib.types; nullOr str;
description = lib.mdDoc ''
Specify the path to a file or `AF_UNIX` stream socket to read the
secret server key corresponding to the certificate specified with
{option}`services.journald.gateway.cert` from.

The key must be in PEM format.

This key should not be world-readable, and must be readably by the
`systemd-journal-gateway` user.
'';
};

trust = lib.mkOption {
default = null;
type = with lib.types; nullOr str;
description = lib.mdDoc ''
Specify the path to a file or `AF_UNIX` stream socket to read a CA
certificate from.

The certificate must be in PEM format.

Setting this option enforces client certificate checking.
'';
};

system = lib.mkOption {
default = true;
type = lib.types.bool;
description = lib.mdDoc ''
Serve entries from system services and the kernel.

This has the same meaning as `--system` for {manpage}`journalctl(1)`.
'';
};

user = lib.mkOption {
default = true;
type = lib.types.bool;
description = lib.mdDoc ''
Serve entries from services for the current user.

This has the same meaning as `--user` for {manpage}`journalctl(1)`.
'';
};

merge = lib.mkOption {
default = false;
type = lib.types.bool;
description = lib.mdDoc ''
Serve entries interleaved from all available journals, including other
machines.

This has the same meaning as `--merge` option for
{manpage}`journalctl(1)`.
'';
};
};

config = lib.mkIf cfg.enable {
assertions = [
{
# This prevents the weird case were disabling "system" and "user"
# actually enables both because the cli flags are not present.
assertion = cfg.system || cfg.user;
message = ''
systemd-journal-gatewayd cannot serve neither "system" nor "user"
journals.
'';
}
];

systemd.additionalUpstreamSystemUnits = [
"systemd-journal-gatewayd.socket"
"systemd-journal-gatewayd.service"
];

users.users.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
users.users.systemd-journal-gateway.group = "systemd-journal-gateway";
users.groups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;

systemd.services.systemd-journal-gatewayd.serviceConfig.ExecStart = [
# Clear the default command line
""
"${pkgs.systemd}/lib/systemd/systemd-journal-gatewayd ${cliArgs}"
];

systemd.sockets.systemd-journal-gatewayd = {
wantedBy = [ "sockets.target" ];
listenStreams = [
# Clear the default port
""
(toString cfg.port)
];
};
};
}
163 changes: 163 additions & 0 deletions nixos/modules/system/boot/systemd/journald-remote.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
{ config, lib, pkgs, ... }:

let
cfg = config.services.journald.remote;
format = pkgs.formats.systemd;

cliArgs = lib.cli.toGNUCommandLineShell { } {
inherit (cfg) output;
# "-3" specifies the file descriptor from the .socket unit.
"listen-${cfg.listen}" = "-3";
};
in
{
meta.maintainers = [ lib.maintainers.raitobezarius ];
options.services.journald.remote = {
enable = lib.mkEnableOption "receiving systemd journals from the network";

listen = lib.mkOption {
default = "https";
type = lib.types.enum [ "https" "http" ];
description = lib.mdDoc ''
Which protocol to listen to.
'';
};

output = lib.mkOption {
default = "/var/log/journal/remote/";
type = lib.types.str;
description = lib.mdDoc ''
The location of the output journal.

In case the output file is not specified, journal files will be created
underneath the selected directory. Files will be called
{file}`remote-hostname.journal`, where the `hostname` part is the
escaped hostname of the source endpoint of the connection, or the
numerical address if the hostname cannot be determined.
'';
};

port = lib.mkOption {
default = 19532;
type = lib.types.port;
description = ''
The port to listen to.

Note that this option is used only if
{option}`services.journald.upload.listen` is configured to be either
"https" or "http".
'';
};

settings = lib.mkOption {
default = { };

description = lib.mdDoc ''
Configuration in the journal-remote configuration file. See
{manpage}`journal-remote.conf(5)` for available options.
'';

type = lib.types.submodule {
freeformType = format.type;

options.Remote = {
Seal = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
description = ''
Periodically sign the data in the journal using Forward Secure
Sealing.
'';
};

SplitMode = lib.mkOption {
default = "host";
example = "none";
type = lib.types.enum [ "host" "none" ];
description = lib.mdDoc ''
With "host", a separate output file is used, based on the
hostname of the other endpoint of a connection. With "none", only
one output journal file is used.
'';
};

ServerKeyFile = lib.mkOption {
default = "/etc/ssl/private/journal-remote.pem";
type = lib.types.str;
description = lib.mdDoc ''
A path to a SSL secret key file in PEM format.

Note that due to security reasons, `systemd-journal-remote` will
refuse files from the world-readable `/nix/store`. This file
should be readable by the "" user.

This option can be used with `listen = "https"`. If the path
refers to an `AF_UNIX` stream socket in the file system a
connection is made to it and the key read from it.
'';
};

ServerCertificateFile = lib.mkOption {
default = "/etc/ssl/certs/journal-remote.pem";
type = lib.types.str;
description = lib.mdDoc ''
A path to a SSL certificate file in PEM format.

This option can be used with `listen = "https"`. If the path
refers to an `AF_UNIX` stream socket in the file system a
connection is made to it and the certificate read from it.
'';
};

TrustedCertificateFile = lib.mkOption {
default = "/etc/ssl/ca/trusted.pem";
type = lib.types.str;
description = lib.mdDoc ''
A path to a SSL CA certificate file in PEM format, or `all`.

If `all` is set, then client certificate checking will be
disabled.

This option can be used with `listen = "https"`. If the path
refers to an `AF_UNIX` stream socket in the file system a
connection is made to it and the certificate read from it.
'';
};
};
};
};
};

config = lib.mkIf cfg.enable {
systemd.additionalUpstreamSystemUnits = [
"systemd-journal-remote.service"
"systemd-journal-remote.socket"
];

systemd.services.systemd-journal-remote.serviceConfig.ExecStart = [
# Clear the default command line
""
"${pkgs.systemd}/lib/systemd/systemd-journal-remote ${cliArgs}"
];

systemd.sockets.systemd-journal-remote = {
wantedBy = [ "sockets.target" ];
listenStreams = [
# Clear the default port
""
(toString cfg.port)
];
};

# User and group used by systemd-journal-remote.service
users.groups.systemd-journal-remote = { };
users.users.systemd-journal-remote = {
isSystemUser = true;
group = "systemd-journal-remote";
};

environment.etc."systemd/journal-remote.conf".source =
format.generate "journal-remote.conf" cfg.settings;
};
}
Loading