nixos/scion: init

This commit is contained in:
matthewcroughan 2024-03-24 21:03:03 +00:00
parent d3b17d0b54
commit 99e488e2df
14 changed files with 727 additions and 0 deletions

View File

@ -1107,6 +1107,11 @@
./services/networking/rpcbind.nix
./services/networking/rxe.nix
./services/networking/sabnzbd.nix
./services/networking/scion/scion.nix
./services/networking/scion/scion-control.nix
./services/networking/scion/scion-daemon.nix
./services/networking/scion/scion-dispatcher.nix
./services/networking/scion/scion-router.nix
./services/networking/seafile.nix
./services/networking/searx.nix
./services/networking/shadowsocks.nix

View File

@ -0,0 +1,69 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.scion.scion-control;
toml = pkgs.formats.toml { };
defaultConfig = {
general = {
id = "cs";
config_dir = "/etc/scion";
reconnect_to_dispatcher = true;
};
beacon_db = {
connection = "/var/lib/scion-control/control.beacon.db";
};
path_db = {
connection = "/var/lib/scion-control/control.path.db";
};
trust_db = {
connection = "/var/lib/scion-control/control.trust.db";
};
log.console = {
level = "info";
};
};
configFile = toml.generate "scion-control.toml" (defaultConfig // cfg.settings);
in
{
options.services.scion.scion-control = {
enable = mkEnableOption (lib.mdDoc "the scion-control service");
settings = mkOption {
default = { };
type = toml.type;
example = literalExpression ''
{
path_db = {
connection = "/var/lib/scion-control/control.path.db";
};
log.console = {
level = "info";
};
}
'';
description = lib.mdDoc ''
scion-control configuration. Refer to
<https://docs.scion.org/en/latest/manuals/common.html>
for details on supported values.
'';
};
};
config = mkIf cfg.enable {
systemd.services.scion-control = {
description = "SCION Control Service";
after = [ "network-online.target" "scion-dispatcher.service" ];
wants = [ "network-online.target" "scion-dispatcher.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
Group = if (config.services.scion.scion-dispatcher.enable == true) then "scion" else null;
ExecStart = "${pkgs.scion}/bin/scion-control --config ${configFile}";
DynamicUser = true;
Restart = "on-failure";
BindPaths = [ "/dev/shm:/run/shm" ];
StateDirectory = "scion-control";
};
};
};
}

View File

@ -0,0 +1,64 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.scion.scion-daemon;
toml = pkgs.formats.toml { };
defaultConfig = {
general = {
id = "sd";
config_dir = "/etc/scion";
reconnect_to_dispatcher = true;
};
path_db = {
connection = "/var/lib/scion-daemon/sd.path.db";
};
trust_db = {
connection = "/var/lib/scion-daemon/sd.trust.db";
};
log.console = {
level = "info";
};
};
configFile = toml.generate "scion-daemon.toml" (defaultConfig // cfg.settings);
in
{
options.services.scion.scion-daemon = {
enable = mkEnableOption (lib.mdDoc "the scion-daemon service");
settings = mkOption {
default = { };
type = toml.type;
example = literalExpression ''
{
path_db = {
connection = "/var/lib/scion-daemon/sd.path.db";
};
log.console = {
level = "info";
};
}
'';
description = lib.mdDoc ''
scion-daemon configuration. Refer to
<https://docs.scion.org/en/latest/manuals/common.html>
for details on supported values.
'';
};
};
config = mkIf cfg.enable {
systemd.services.scion-daemon = {
description = "SCION Daemon";
after = [ "network-online.target" "scion-dispatcher.service" ];
wants = [ "network-online.target" "scion-dispatcher.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.scion}/bin/scion-daemon --config ${configFile}";
Restart = "on-failure";
DynamicUser = true;
StateDirectory = "scion-daemon";
};
};
};
}

View File

@ -0,0 +1,74 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.scion.scion-dispatcher;
toml = pkgs.formats.toml { };
defaultConfig = {
dispatcher = {
id = "dispatcher";
socket_file_mode = "0770";
application_socket = "/dev/shm/dispatcher/default.sock";
};
log.console = {
level = "info";
};
};
configFile = toml.generate "scion-dispatcher.toml" (defaultConfig // cfg.settings);
in
{
options.services.scion.scion-dispatcher = {
enable = mkEnableOption (lib.mdDoc "the scion-dispatcher service");
settings = mkOption {
default = { };
type = toml.type;
example = literalExpression ''
{
dispatcher = {
id = "dispatcher";
socket_file_mode = "0770";
application_socket = "/dev/shm/dispatcher/default.sock";
};
log.console = {
level = "info";
};
}
'';
description = lib.mdDoc ''
scion-dispatcher configuration. Refer to
<https://docs.scion.org/en/latest/manuals/common.html>
for details on supported values.
'';
};
};
config = mkIf cfg.enable {
# Needed for group ownership of the dispatcher socket
users.groups.scion = {};
# scion programs hardcode path to dispatcher in /run/shm, and is not
# configurable at runtime upstream plans to obsolete the dispatcher in
# favor of an SCMP daemon, at which point this can be removed.
system.activationScripts.scion-dispatcher = ''
ln -sf /dev/shm /run/shm
'';
systemd.services.scion-dispatcher = {
description = "SCION Dispatcher";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
Group = "scion";
DynamicUser = true;
BindPaths = [ "/dev/shm:/run/shm" ];
ExecStartPre = "${pkgs.coreutils}/bin/rm -rf /run/shm/dispatcher";
ExecStart = "${pkgs.scion}/bin/scion-dispatcher --config ${configFile}";
Restart = "on-failure";
StateDirectory = "scion-dispatcher";
};
};
};
}

View File

@ -0,0 +1,49 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.scion.scion-router;
toml = pkgs.formats.toml { };
defaultConfig = {
general = {
id = "br";
config_dir = "/etc/scion";
};
};
configFile = toml.generate "scion-router.toml" (defaultConfig // cfg.settings);
in
{
options.services.scion.scion-router = {
enable = mkEnableOption (lib.mdDoc "the scion-router service");
settings = mkOption {
default = { };
type = toml.type;
example = literalExpression ''
{
general.id = "br";
}
'';
description = lib.mdDoc ''
scion-router configuration. Refer to
<https://docs.scion.org/en/latest/manuals/common.html>
for details on supported values.
'';
};
};
config = mkIf cfg.enable {
systemd.services.scion-router = {
description = "SCION Router";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.scion}/bin/scion-router --config ${configFile}";
Restart = "on-failure";
DynamicUser = true;
StateDirectory = "scion-router";
};
};
};
}

View File

@ -0,0 +1,39 @@
{ config, lib, ... }:
with lib;
let
cfg = config.services.scion;
in
{
options.services.scion = {
enable = mkEnableOption (lib.mdDoc "all of the scion components and services");
bypassBootstrapWarning = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
bypass Nix warning about SCION PKI bootstrapping
'';
};
};
config = mkIf cfg.enable {
services.scion = {
scion-dispatcher.enable = true;
scion-daemon.enable = true;
scion-router.enable = true;
scion-control.enable = true;
};
assertions = [
{ assertion = cfg.bypassBootstrapWarning == true;
message = ''
SCION is a routing protocol and requires bootstrapping with a manual, imperative key signing ceremony. You may want to join an existing Isolation Domain (ISD) such as scionlab.org, or bootstrap your own. If you have completed and configured the public key infrastructure for SCION and are sure this process is complete, then add the following to your configuration:
services.scion.bypassBootstrapWarning = true;
refer to docs.scion.org for more information
'';
}
];
};
}

View File

@ -791,6 +791,7 @@ in {
sanoid = handleTest ./sanoid.nix {};
scaphandre = handleTest ./scaphandre.nix {};
schleuder = handleTest ./schleuder.nix {};
scion-freestanding-deployment = handleTest ./scion/freestanding-deployment {};
scrutiny = handleTest ./scrutiny.nix {};
sddm = handleTest ./sddm.nix {};
seafile = handleTest ./seafile.nix {};

View File

@ -0,0 +1,12 @@
This NixOS VM test implements the network topology outlined in https://github.com/scionproto/scion/blob/27983125bccac6b84d1f96f406853aab0e460405/doc/tutorials/deploy.rst#sample-scion-demo-topology, below is an excerpt from that document
Sample SCION Demo Topology
..........................
The topology of the ISD includes the inter-AS connections to neighboring ASes, and defines the underlay IP/UDP addresses of services and routers running in this AS. This is specified in topology files - this guide later explains how to configure these files. A following graphic depicts the topology on a high level.
.. figure:: https://github.com/scionproto/scion/raw/27983125bccac6b84d1f96f406853aab0e460405/doc/tutorials/deploy/SCION-deployment-guide.drawio.png
:width: 95 %
:figwidth: 100 %
*Figure 1 - Topology of the sample SCION demo environment. It consists of 1 ISD, 3 core ASes and 2 non-core ASes.*

View File

@ -0,0 +1,172 @@
# implements https://github.com/scionproto/scion/blob/27983125bccac6b84d1f96f406853aab0e460405/doc/tutorials/deploy.rst
import ../../make-test-python.nix ({ pkgs, ... }:
let
trust-root-configuration-keys = pkgs.runCommand "generate-trc-keys.sh" {
buildInputs = [
pkgs.scion
];
} ''
set -euo pipefail
mkdir /tmp/tutorial-scion-certs && cd /tmp/tutorial-scion-certs
mkdir AS{1..5}
# Create voting and root keys and (self-signed) certificates for core ASes
pushd AS1
scion-pki certificate create --not-after=3650d --profile=sensitive-voting <(echo '{"isd_as": "42-ffaa:1:1", "common_name": "42-ffaa:1:1 sensitive voting cert"}') sensitive-voting.pem sensitive-voting.key
scion-pki certificate create --not-after=3650d --profile=regular-voting <(echo '{"isd_as": "42-ffaa:1:1", "common_name": "42-ffaa:1:1 regular voting cert"}') regular-voting.pem regular-voting.key
scion-pki certificate create --not-after=3650d --profile=cp-root <(echo '{"isd_as": "42-ffaa:1:1", "common_name": "42-ffaa:1:1 cp root cert"}') cp-root.pem cp-root.key
popd
pushd AS2
scion-pki certificate create --not-after=3650d --profile=cp-root <(echo '{"isd_as": "42-ffaa:1:2", "common_name": "42-ffaa:1:2 cp root cert"}') cp-root.pem cp-root.key
popd
pushd AS3
scion-pki certificate create --not-after=3650d --profile=sensitive-voting <(echo '{"isd_as": "42-ffaa:1:3", "common_name": "42-ffaa:1:3 sensitive voting cert"}') sensitive-voting.pem sensitive-voting.key
scion-pki certificate create --not-after=3650d --profile=regular-voting <(echo '{"isd_as": "42-ffaa:1:3", "common_name": "42-ffaa:1:3 regular voting cert"}') regular-voting.pem regular-voting.key
popd
# Create the TRC (Trust Root Configuration)
mkdir tmp
echo '
isd = 42
description = "Demo ISD 42"
serial_version = 1
base_version = 1
voting_quorum = 2
core_ases = ["ffaa:1:1", "ffaa:1:2", "ffaa:1:3"]
authoritative_ases = ["ffaa:1:1", "ffaa:1:2", "ffaa:1:3"]
cert_files = ["AS1/sensitive-voting.pem", "AS1/regular-voting.pem", "AS1/cp-root.pem", "AS2/cp-root.pem", "AS3/sensitive-voting.pem", "AS3/regular-voting.pem"]
[validity]
not_before = '$(date +%s)'
validity = "365d"' \
> trc-B1-S1-pld.tmpl
scion-pki trc payload --out=tmp/ISD42-B1-S1.pld.der --template trc-B1-S1-pld.tmpl
rm trc-B1-S1-pld.tmpl
# Sign and bundle the TRC
scion-pki trc sign tmp/ISD42-B1-S1.pld.der AS1/sensitive-voting.{pem,key} --out tmp/ISD42-B1-S1.AS1-sensitive.trc
scion-pki trc sign tmp/ISD42-B1-S1.pld.der AS1/regular-voting.{pem,key} --out tmp/ISD42-B1-S1.AS1-regular.trc
scion-pki trc sign tmp/ISD42-B1-S1.pld.der AS3/sensitive-voting.{pem,key} --out tmp/ISD42-B1-S1.AS3-sensitive.trc
scion-pki trc sign tmp/ISD42-B1-S1.pld.der AS3/regular-voting.{pem,key} --out tmp/ISD42-B1-S1.AS3-regular.trc
scion-pki trc combine tmp/ISD42-B1-S1.AS{1,3}-{sensitive,regular}.trc --payload tmp/ISD42-B1-S1.pld.der --out ISD42-B1-S1.trc
rm tmp -r
# Create CA key and certificate for issuing ASes
pushd AS1
scion-pki certificate create --profile=cp-ca <(echo '{"isd_as": "42-ffaa:1:1", "common_name": "42-ffaa:1:1 CA cert"}') cp-ca.pem cp-ca.key --ca cp-root.pem --ca-key cp-root.key
popd
pushd AS2
scion-pki certificate create --profile=cp-ca <(echo '{"isd_as": "42-ffaa:1:2", "common_name": "42-ffaa:1:2 CA cert"}') cp-ca.pem cp-ca.key --ca cp-root.pem --ca-key cp-root.key
popd
# Create AS key and certificate chains
scion-pki certificate create --profile=cp-as <(echo '{"isd_as": "42-ffaa:1:1", "common_name": "42-ffaa:1:1 AS cert"}') AS1/cp-as.pem AS1/cp-as.key --ca AS1/cp-ca.pem --ca-key AS1/cp-ca.key --bundle
scion-pki certificate create --profile=cp-as <(echo '{"isd_as": "42-ffaa:1:2", "common_name": "42-ffaa:1:2 AS cert"}') AS2/cp-as.pem AS2/cp-as.key --ca AS2/cp-ca.pem --ca-key AS2/cp-ca.key --bundle
scion-pki certificate create --profile=cp-as <(echo '{"isd_as": "42-ffaa:1:3", "common_name": "42-ffaa:1:3 AS cert"}') AS3/cp-as.pem AS3/cp-as.key --ca AS1/cp-ca.pem --ca-key AS1/cp-ca.key --bundle
scion-pki certificate create --profile=cp-as <(echo '{"isd_as": "42-ffaa:1:4", "common_name": "42-ffaa:1:4 AS cert"}') AS4/cp-as.pem AS4/cp-as.key --ca AS1/cp-ca.pem --ca-key AS1/cp-ca.key --bundle
scion-pki certificate create --profile=cp-as <(echo '{"isd_as": "42-ffaa:1:5", "common_name": "42-ffaa:1:5 AS cert"}') AS5/cp-as.pem AS5/cp-as.key --ca AS2/cp-ca.pem --ca-key AS2/cp-ca.key --bundle
for i in {1..5}
do
mkdir -p $out/AS$i
cp AS$i/cp-as.{key,pem} $out/AS$i
done
mv *.trc $out
'';
imports = hostId: [
({
services.scion = {
enable = true;
bypassBootstrapWarning = true;
};
networking = {
useNetworkd = true;
useDHCP = false;
};
systemd.network.networks."01-eth1" = {
name = "eth1";
networkConfig.Address = "192.168.1.${toString hostId}/24";
};
environment.etc = {
"scion/topology.json".source = ./topology${toString hostId}.json;
"scion/crypto/as".source = trust-root-configuration-keys + "/AS${toString hostId}";
"scion/certs/ISD42-B1-S1.trc".source = trust-root-configuration-keys + "/ISD42-B1-S1.trc";
"scion/keys/master0.key".text = "U${toString hostId}v4k23ZXjGDwDofg/Eevw==";
"scion/keys/master1.key".text = "dBMko${toString hostId}qMS8DfrN/zP2OUdA==";
};
environment.systemPackages = [
pkgs.scion
];
})
];
in
{
name = "scion-test";
nodes = {
scion01 = { ... }: {
imports = (imports 1);
};
scion02 = { ... }: {
imports = (imports 2);
};
scion03 = { ... }: {
imports = (imports 3);
};
scion04 = { ... }: {
imports = (imports 4);
};
scion05 = { ... }: {
imports = (imports 5);
};
};
testScript = let
pingAll = pkgs.writeShellScript "ping-all-scion.sh" ''
addresses="42-ffaa:1:1 42-ffaa:1:2 42-ffaa:1:3 42-ffaa:1:4 42-ffaa:1:5"
timeout=100
wait_for_all() {
for as in "$@"
do
scion showpaths $as --no-probe > /dev/null
return 1
done
return 0
}
ping_all() {
for as in "$@"
do
scion ping "$as,127.0.0.1" -c 3
done
return 0
}
for i in $(seq 0 $timeout); do
wait_for_all $addresses && exit 0
ping_all $addresses && exit 0
sleep 1
done
'';
in
''
# List of AS instances
machines = [scion01, scion02, scion03, scion04, scion05]
# Wait for scion-control.service on all instances
for i in machines:
i.wait_for_unit("scion-control.service")
# Execute pingAll command on all instances
for i in machines:
i.succeed("${pingAll} >&2")
# Restart scion-dispatcher and ping again to test robustness
for i in machines:
i.succeed("systemctl restart scion-dispatcher >&2")
i.succeed("${pingAll} >&2")
'';
})

View File

@ -0,0 +1,51 @@
{
"attributes": [
"core"
],
"isd_as": "42-ffaa:1:1",
"mtu": 1472,
"control_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"discovery_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"border_routers": {
"br": {
"internal_addr": "127.0.0.1:31002",
"interfaces": {
"1": {
"underlay": {
"public": "192.168.1.1:50014",
"remote": "192.168.1.4:50014"
},
"isd_as": "42-ffaa:1:4",
"link_to": "child",
"mtu": 1472
},
"2": {
"underlay": {
"public": "192.168.1.1:50012",
"remote": "192.168.1.2:50012"
},
"isd_as": "42-ffaa:1:2",
"link_to": "core",
"mtu": 1472
},
"3": {
"underlay": {
"public": "192.168.1.1:50013",
"remote": "192.168.1.3:50013"
},
"isd_as": "42-ffaa:1:3",
"link_to": "core",
"mtu": 1472
}
}
}
}
}

View File

@ -0,0 +1,51 @@
{
"attributes": [
"core"
],
"isd_as": "42-ffaa:1:2",
"mtu": 1472,
"control_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"discovery_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"border_routers": {
"br": {
"internal_addr": "127.0.0.1:31002",
"interfaces": {
"1": {
"underlay": {
"public": "192.168.1.2:50012",
"remote": "192.168.1.1:50012"
},
"isd_as": "42-ffaa:1:1",
"link_to": "core",
"mtu": 1472
},
"2": {
"underlay": {
"public": "192.168.1.2:50023",
"remote": "192.168.1.3:50023"
},
"isd_as": "42-ffaa:1:3",
"link_to": "core",
"mtu": 1472
},
"3": {
"underlay": {
"public": "192.168.1.2:50025",
"remote": "192.168.1.5:50025"
},
"isd_as": "42-ffaa:1:5",
"link_to": "child",
"mtu": 1472
}
}
}
}
}

View File

@ -0,0 +1,60 @@
{
"attributes": [
"core"
],
"isd_as": "42-ffaa:1:3",
"mtu": 1472,
"control_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"discovery_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"border_routers": {
"br": {
"internal_addr": "127.0.0.1:31002",
"interfaces": {
"1": {
"underlay": {
"public": "192.168.1.3:50013",
"remote": "192.168.1.1:50013"
},
"isd_as": "42-ffaa:1:1",
"link_to": "core",
"mtu": 1472
},
"2": {
"underlay": {
"public": "192.168.1.3:50023",
"remote": "192.168.1.2:50023"
},
"isd_as": "42-ffaa:1:2",
"link_to": "core",
"mtu": 1472
},
"3": {
"underlay": {
"public": "192.168.1.3:50034",
"remote": "192.168.1.4:50034"
},
"isd_as": "42-ffaa:1:4",
"link_to": "child",
"mtu": 1472
},
"4": {
"underlay": {
"public": "192.168.1.3:50035",
"remote": "192.168.1.5:50035"
},
"isd_as": "42-ffaa:1:5",
"link_to": "child",
"mtu": 1472
}
}
}
}
}

View File

@ -0,0 +1,40 @@
{
"attributes": [],
"isd_as": "42-ffaa:1:4",
"mtu": 1472,
"control_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"discovery_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"border_routers": {
"br": {
"internal_addr": "127.0.0.1:31002",
"interfaces": {
"1": {
"underlay": {
"public": "192.168.1.4:50014",
"remote": "192.168.1.1:50014"
},
"isd_as": "42-ffaa:1:1",
"link_to": "parent",
"mtu": 1472
},
"2": {
"underlay": {
"public": "192.168.1.4:50034",
"remote": "192.168.1.3:50034"
},
"isd_as": "42-ffaa:1:3",
"link_to": "parent",
"mtu": 1472
}
}
}
}
}

View File

@ -0,0 +1,40 @@
{
"attributes": [],
"isd_as": "42-ffaa:1:5",
"mtu": 1472,
"control_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"discovery_service": {
"cs": {
"addr": "127.0.0.1:31000"
}
},
"border_routers": {
"br": {
"internal_addr": "127.0.0.1:31002",
"interfaces": {
"1": {
"underlay": {
"public": "192.168.1.5:50025",
"remote": "192.168.1.2:50025"
},
"isd_as": "42-ffaa:1:2",
"link_to": "parent",
"mtu": 1472
},
"2": {
"underlay": {
"public": "192.168.1.5:50035",
"remote": "192.168.1.3:50035"
},
"isd_as": "42-ffaa:1:3",
"link_to": "parent",
"mtu": 1472
}
}
}
}
}