WIP: ap01-prepare-poc #280
24 changed files with 422 additions and 201 deletions
|
@ -187,11 +187,17 @@ in
|
||||||
}))
|
}))
|
||||||
pkgs.npins
|
pkgs.npins
|
||||||
|
|
||||||
|
pkgs.rage
|
||||||
|
|
||||||
# SSO testing
|
# SSO testing
|
||||||
pkgs.kanidm
|
pkgs.kanidm
|
||||||
pkgs.freeradius
|
pkgs.freeradius
|
||||||
pkgs.picocom # for serial access
|
pkgs.picocom # for serial access
|
||||||
|
|
||||||
|
# Daemon-less copy closure for Liminix systems.
|
||||||
|
(pkgs.callPackage (sources.liminix + "/pkgs/min-copy-closure") { nix = pkgs.lix; })
|
||||||
|
# Daemon-less garbage collection for Liminix systems.
|
||||||
|
(pkgs.callPackage (sources.liminix + "/pkgs/min-collect-garbage") { nix = pkgs.lix; })
|
||||||
(pkgs.callPackage ./lib/colmena {
|
(pkgs.callPackage ./lib/colmena {
|
||||||
colmena = pkgs.callPackage "${sources.colmena}/package.nix" { };
|
colmena = pkgs.callPackage "${sources.colmena}/package.nix" { };
|
||||||
})
|
})
|
||||||
|
|
4
hive.nix
4
hive.nix
|
@ -111,12 +111,12 @@ in
|
||||||
args;
|
args;
|
||||||
|
|
||||||
defaults =
|
defaults =
|
||||||
{ name, nodePath, ... }:
|
{ name, ... }:
|
||||||
{
|
{
|
||||||
# Import the default modules
|
# Import the default modules
|
||||||
imports = [
|
imports = [
|
||||||
# Import the base configuration for each node
|
# Import the base configuration for each node
|
||||||
./${nodePath}/_configuration.nix
|
./machines/liminix/ap-v01/_configuration.nix
|
||||||
./modules/generic
|
./modules/generic
|
||||||
./modules/${category name}
|
./modules/${category name}
|
||||||
];
|
];
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
{
|
{
|
||||||
modulesPath,
|
modulesPath,
|
||||||
sourcePkgs,
|
sourcePkgs,
|
||||||
|
name,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
"${modulesPath}/wlan.nix"
|
"${modulesPath}/wlan.nix"
|
||||||
"${modulesPath}/network"
|
"${modulesPath}/network"
|
||||||
"${modulesPath}/hostapd"
|
"${modulesPath}/hostapd"
|
||||||
|
"${modulesPath}/usteer"
|
||||||
"${modulesPath}/ssh"
|
"${modulesPath}/ssh"
|
||||||
"${modulesPath}/ntp"
|
"${modulesPath}/ntp"
|
||||||
"${modulesPath}/vlan"
|
"${modulesPath}/vlan"
|
||||||
|
@ -29,6 +31,8 @@
|
||||||
./addresses.nix
|
./addresses.nix
|
||||||
# Configures a basic local DNS.
|
# Configures a basic local DNS.
|
||||||
./dns.nix
|
./dns.nix
|
||||||
|
# Add ubus daemon
|
||||||
|
./ipc.nix
|
||||||
# Configures our management layer, e.g. SSH server + DGNum FAI keys.
|
# Configures our management layer, e.g. SSH server + DGNum FAI keys.
|
||||||
./management.nix
|
./management.nix
|
||||||
# Configures our recovery system, e.g. a levitation script.
|
# Configures our recovery system, e.g. a levitation script.
|
||||||
|
@ -39,6 +43,6 @@
|
||||||
(import "${modulesPath}/../devices/zyxel-nwa50ax").module
|
(import "${modulesPath}/../devices/zyxel-nwa50ax").module
|
||||||
];
|
];
|
||||||
|
|
||||||
hostname = "ap01-prototype";
|
hostname = name;
|
||||||
nixpkgs.source = sourcePkgs.path;
|
nixpkgs.source = sourcePkgs.path;
|
||||||
}
|
}
|
25
machines/liminix/ap-v01/addresses.nix
Normal file
25
machines/liminix/ap-v01/addresses.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
{ config, nodeMeta, ... }:
|
||||||
|
let
|
||||||
|
svc = config.system.service;
|
||||||
|
inherit (nodeMeta.extraNodeSettings) building floor ap-no;
|
||||||
|
# FIXME switch to ipv6 tu be able to scale
|
||||||
|
adminIp = "10.0.253.${builtins.toString (ap-no + floor * 8 + building * 32 + 2)}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.admin-ip = svc.network.address.build {
|
||||||
|
interface = config.services.admin-vlan;
|
||||||
|
address = adminIp;
|
||||||
|
prefixLength = 24;
|
||||||
|
family = "inet";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.admin-defaultroute4 = svc.network.route.build {
|
||||||
|
via = "10.0.253.1";
|
||||||
|
target = "default";
|
||||||
|
dependencies = [ config.services.admin-ip ];
|
||||||
|
};
|
||||||
|
}
|
25
machines/liminix/ap-v01/dns.nix
Normal file
25
machines/liminix/ap-v01/dns.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
|
# TODO: imho, DNS should be static and provided by the router?
|
||||||
|
dns = [
|
||||||
|
"8.8.8.8"
|
||||||
|
"8.8.4.4"
|
||||||
|
"1.0.0.1"
|
||||||
|
];
|
||||||
|
resolvconf = pkgs.writeText "resolv.conf" (
|
||||||
|
lib.concatMapStringsSep "\n" (dns: ''echo "nameserver ${dns}" >> resolv.conf'') dns
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# TODO: support dynamic reconfiguration once we are in the target VLAN?
|
||||||
|
filesystem = dir {
|
||||||
|
etc = dir {
|
||||||
|
"resolv.conf" = symlink "${resolvconf}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
20
machines/liminix/ap-v01/lan.nix
Normal file
20
machines/liminix/ap-v01/lan.nix
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
{ config, ... }:
|
||||||
|
let
|
||||||
|
svc = config.system.service;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Our bridging is a bit complicated, therefore, we need iproute2.
|
||||||
|
programs.iproute2.enable = true;
|
||||||
|
|
||||||
|
services = {
|
||||||
|
admin-vlan = svc.vlan.build {
|
||||||
|
ifname = "admin";
|
||||||
|
primary = config.hardware.networkInterfaces.lan;
|
||||||
|
vid = "3001";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ in
|
||||||
# SSH keys are handled by the access control module.
|
# SSH keys are handled by the access control module.
|
||||||
dgn-access-control.enable = true;
|
dgn-access-control.enable = true;
|
||||||
users.root = {
|
users.root = {
|
||||||
|
# TODO: Change this well-known password
|
||||||
passwd = "$6$Z2MiaMXkpUJRPl2/$fxVE3iD/n208CISM2F6OnWj0Qq0QG2tTQqLCjU80PFJJGIwNLLyOp6SeYH3dH20OvJX1loZRETrThZfIPw.rb/";
|
passwd = "$6$Z2MiaMXkpUJRPl2/$fxVE3iD/n208CISM2F6OnWj0Qq0QG2tTQqLCjU80PFJJGIwNLLyOp6SeYH3dH20OvJX1loZRETrThZfIPw.rb/";
|
||||||
};
|
};
|
||||||
services.sshd = svc.ssh.build { allowRoot = true; };
|
services.sshd = svc.ssh.build { allowRoot = true; };
|
68
machines/liminix/ap-v01/recovery.nix
Normal file
68
machines/liminix/ap-v01/recovery.nix
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
svc = config.system.service;
|
||||||
|
parentConfig = config;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
defaultProfile.packages = [
|
||||||
|
# Levitate enable us to mass-reinstall the system on the fly.
|
||||||
|
# TODO: Test levitation
|
||||||
|
(pkgs.levitate.override {
|
||||||
|
config = {
|
||||||
|
imports = [
|
||||||
|
"${modulesPath}/network"
|
||||||
|
"${modulesPath}/ssh"
|
||||||
|
"${modulesPath}/hardware.nix"
|
||||||
|
"${modulesPath}/kernel"
|
||||||
|
"${modulesPath}/outputs/tftpboot.nix"
|
||||||
|
"${modulesPath}/outputs.nix"
|
||||||
|
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
|
||||||
|
"${modulesPath}/iproute2.nix"
|
||||||
|
(
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
|
||||||
|
programs.iproute2.enable = true;
|
||||||
|
services = {
|
||||||
|
# In this situation, we fallback to the appro VLAN but keep admin vlan.
|
||||||
|
# Simplest DHCPv4 we can find.
|
||||||
|
dhcpv4 = svc.network.dhcp.client.build {
|
||||||
|
interface = parentConfig.hardware.networkInterfaces.lan;
|
||||||
|
};
|
||||||
|
inherit (parentConfig.services)
|
||||||
|
sshd
|
||||||
|
admin-vlan
|
||||||
|
admin-ip
|
||||||
|
admin-defaultroute4
|
||||||
|
;
|
||||||
|
defaultroute4 = svc.network.route.build {
|
||||||
|
via = "$(output ${config.services.dhcpv4} router)";
|
||||||
|
target = "default";
|
||||||
|
dependencies = [ config.services.dhcpv4 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
hostname = "${parentConfig.hostname}-live";
|
||||||
|
nixpkgs.buildPlatform = builtins.currentSystem;
|
||||||
|
|
||||||
|
defaultProfile.packages = with pkgs; [
|
||||||
|
mtdutils
|
||||||
|
zyxel-bootconfig
|
||||||
|
];
|
||||||
|
# Only keep root, which should inherit from DGN access control's root permissions.
|
||||||
|
users.root = config.users.root;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
|
@ -2,14 +2,28 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
{ config, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
nodeMeta,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
svc = config.system.service;
|
svc = config.system.service;
|
||||||
|
|
||||||
|
inherit (nodeMeta.extraNodeSettings) building floor ap-no;
|
||||||
|
|
||||||
|
hex = x: lib.fixedWidthString 2 "0" (lib.toHexString x);
|
||||||
|
|
||||||
|
mac-1 = "02:5B:6A:${hex (building * 4)}:${hex floor}:${hex ap-no}";
|
||||||
|
mac-2 = "02:5B:6A:${hex (building * 4 + 1)}:${hex floor}:${hex ap-no}";
|
||||||
|
|
||||||
secrets-1 = {
|
secrets-1 = {
|
||||||
ssid = "DGNum 2G (N)";
|
ssid = "DGNum";
|
||||||
};
|
};
|
||||||
secrets-2 = {
|
secrets-2 = {
|
||||||
ssid = "DGNum 5G (AX)";
|
ssid = "DGNum";
|
||||||
};
|
};
|
||||||
baseParams = {
|
baseParams = {
|
||||||
country_code = "FR";
|
country_code = "FR";
|
||||||
|
@ -42,7 +56,7 @@ let
|
||||||
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
|
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
|
||||||
vht_oper_chwidth = 1;
|
vht_oper_chwidth = 1;
|
||||||
he_oper_chwidth = 1;
|
he_oper_chwidth = 1;
|
||||||
channel = 36;
|
channel = 36; # TODO understand interferences
|
||||||
vht_oper_centr_freq_seg0_idx = 42;
|
vht_oper_centr_freq_seg0_idx = 42;
|
||||||
he_oper_centr_freq_seg0_idx = 42;
|
he_oper_centr_freq_seg0_idx = 42;
|
||||||
require_vht = 1;
|
require_vht = 1;
|
||||||
|
@ -52,7 +66,7 @@ let
|
||||||
ieee8021x = 1;
|
ieee8021x = 1;
|
||||||
eapol_version = 2;
|
eapol_version = 2;
|
||||||
use_pae_group_addr = 1;
|
use_pae_group_addr = 1;
|
||||||
dynamic_vlan = 0;
|
dynamic_vlan = 3;
|
||||||
vlan_tagged_interface = "lan";
|
vlan_tagged_interface = "lan";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,7 +78,14 @@ let
|
||||||
# No DNS here, hostapd do not support this mode.
|
# No DNS here, hostapd do not support this mode.
|
||||||
auth_server_addr = "129.199.195.129";
|
auth_server_addr = "129.199.195.129";
|
||||||
auth_server_port = 1812;
|
auth_server_port = 1812;
|
||||||
auth_server_shared_secret = "read it online";
|
auth_server_shared_secret =
|
||||||
|
let
|
||||||
|
secret = builtins.getEnv "RADIUS_SECRET";
|
||||||
|
in
|
||||||
|
if secret == "" then
|
||||||
|
lib.warn "Using a dummy RADIUS secret. Please do not use in production" "DUMMYSECRET"
|
||||||
|
else
|
||||||
|
secret;
|
||||||
};
|
};
|
||||||
|
|
||||||
mkWifiSta =
|
mkWifiSta =
|
||||||
|
@ -77,10 +98,14 @@ let
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
hardware.wlanMacAddresses = {
|
||||||
|
wlan0 = mac-1;
|
||||||
|
wlan1 = mac-2;
|
||||||
|
};
|
||||||
services = {
|
services = {
|
||||||
# wlan0 is the 2.4GHz interface.
|
# wlan0 is the 2.4GHz interface.
|
||||||
hostap-1 = mkWifiSta (
|
hostap-1 = mkWifiSta (
|
||||||
baseParams // radiusKeyMgmt
|
baseParams // clientRadius // externalRadius // radiusKeyMgmt
|
||||||
) config.hardware.networkInterfaces.wlan0 secrets-1;
|
) config.hardware.networkInterfaces.wlan0 secrets-1;
|
||||||
hostap-1-ready = svc.hostapd-ready.build {
|
hostap-1-ready = svc.hostapd-ready.build {
|
||||||
interface = config.hardware.networkInterfaces.wlan0;
|
interface = config.hardware.networkInterfaces.wlan0;
|
||||||
|
@ -93,5 +118,14 @@ in
|
||||||
hostap-2-ready = svc.hostapd-ready.build {
|
hostap-2-ready = svc.hostapd-ready.build {
|
||||||
interface = config.hardware.networkInterfaces.wlan1;
|
interface = config.hardware.networkInterfaces.wlan1;
|
||||||
};
|
};
|
||||||
|
usteer = svc.usteer.build {
|
||||||
|
ifname = "lan";
|
||||||
|
dependencies = with config.services; [
|
||||||
|
# FIXME: is it the right stuff to depend on
|
||||||
|
hostap-1-ready
|
||||||
|
hostap-2-ready
|
||||||
|
admin-defaultroute4
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
{ config, ... }:
|
|
||||||
let
|
|
||||||
svc = config.system.service;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.dhcpv4 = svc.network.dhcp.client.build {
|
|
||||||
interface = config.services.int;
|
|
||||||
dependencies = [
|
|
||||||
config.services.bridge.components.lan
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.defaultroute4 = svc.network.route.build {
|
|
||||||
via = "$(output ${config.services.dhcpv4} router)";
|
|
||||||
target = "default";
|
|
||||||
dependencies = [ config.services.dhcpv4 ];
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
{ config, pkgs, ... }:
|
|
||||||
let
|
|
||||||
inherit (pkgs.liminix.services) oneshot;
|
|
||||||
inherit (pkgs.pseudofile) dir symlink;
|
|
||||||
inherit (pkgs) serviceFns;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
# TODO: support dynamic reconfiguration once we are in the target VLAN?
|
|
||||||
services.resolvconf = oneshot rec {
|
|
||||||
name = "resolvconf";
|
|
||||||
up = ''
|
|
||||||
. ${serviceFns}
|
|
||||||
( in_outputs ${name}
|
|
||||||
for i in $(output ${config.services.dhcpv4} dns); do
|
|
||||||
echo "nameserver $i" >> resolv.conf
|
|
||||||
done
|
|
||||||
)
|
|
||||||
'';
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
config.services.dhcpv4
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
filesystem = dir {
|
|
||||||
etc = dir {
|
|
||||||
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
{ config, ... }:
|
|
||||||
let
|
|
||||||
svc = config.system.service;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.int = svc.bridge.primary.build {
|
|
||||||
ifname = "int";
|
|
||||||
macAddressFromInterface = config.hardware.networkInterfaces.lan;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.bridge = svc.bridge.members.build {
|
|
||||||
primary = config.services.int;
|
|
||||||
members = {
|
|
||||||
lan.member = config.hardware.networkInterfaces.lan;
|
|
||||||
wlan0 = {
|
|
||||||
member = config.hardware.networkInterfaces.wlan0;
|
|
||||||
# Bridge only once hostapd is ready.
|
|
||||||
dependencies = [ config.services.hostap-1-ready ];
|
|
||||||
};
|
|
||||||
wlan1 = {
|
|
||||||
member = config.hardware.networkInterfaces.wlan1;
|
|
||||||
# Bridge only once hostapd is ready.
|
|
||||||
dependencies = [ config.services.hostap-2-ready ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Default VLAN
|
|
||||||
# services.vlan-apro = svc.vlan.build {
|
|
||||||
# vlanId = 0;
|
|
||||||
# interface = config.services.int;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# # Administration VLAN
|
|
||||||
# services.vlan-admin = svc.vlan.build {
|
|
||||||
# vlan = 3001;
|
|
||||||
# interface = config.services.int;
|
|
||||||
# };
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
modulesPath,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
svc = config.system.service;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
defaultProfile.packages = with pkgs; [
|
|
||||||
# Levitate enable us to mass-reinstall the system on the fly.
|
|
||||||
(levitate.override {
|
|
||||||
config = {
|
|
||||||
imports = [
|
|
||||||
"${modulesPath}/network"
|
|
||||||
"${modulesPath}/ssh"
|
|
||||||
"${modulesPath}/hardware.nix"
|
|
||||||
"${modulesPath}/kernel"
|
|
||||||
"${modulesPath}/outputs/tftpboot.nix"
|
|
||||||
"${modulesPath}/outputs.nix"
|
|
||||||
];
|
|
||||||
nixpkgs.buildPlatform = builtins.currentSystem;
|
|
||||||
services = {
|
|
||||||
# In this situation, we fallback to the appro VLAN.
|
|
||||||
# TODO: add support for the admin VLAN.
|
|
||||||
# Simplest DHCPv4 we can find.
|
|
||||||
dhcpv4 = svc.network.dhcp.client.build {
|
|
||||||
interface = config.hardware.networkInterfaces.lan;
|
|
||||||
};
|
|
||||||
inherit (config.services) sshd;
|
|
||||||
defaultroute4 = svc.network.route.build {
|
|
||||||
via = "$(output ${config.services.dhcpv4} router)";
|
|
||||||
target = "default";
|
|
||||||
dependencies = [ config.services.dhcpv4 ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultProfile.packages = [ mtdutils ];
|
|
||||||
# Only keep root, which should inherit from DGN access control's root permissions.
|
|
||||||
users.root = config.users.root;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,32 +1,32 @@
|
||||||
age-encryption.org/v1
|
age-encryption.org/v1
|
||||||
-> ssh-ed25519 jIXfPA 2nFaxyP7O4GWU7U3wmET5sNrnFq72b9DEhiKEgWVrFk
|
-> ssh-ed25519 jIXfPA TdfYeqsPJBf26CO1Bh74K8qxqR1MX3VUvZ/e73+oDXQ
|
||||||
l8uXfCBkTHogzVoUY0WOYhA99fodoT+N0HunacULydI
|
KoA/I5kVXxryQ86qjfzq67Aiar+qDZF9OoF4MsNDqe4
|
||||||
-> ssh-ed25519 QlRB9Q qDalihZE404oPOVHYQR5GIvozXNh4wNxhUa5Zwfz2DU
|
-> ssh-ed25519 QlRB9Q ZaPziTdzqf0vCkCiLWAUJbnROaZ7Mz+Xgw1viEMWM2s
|
||||||
X8qvWf7qprbh0xu/uOHGsNLTQc8efYsgveH9R9kZZZw
|
I0peAEQPbaXL9eHQ/OraNuqJPCxIwjpxIxhvgAifATY
|
||||||
-> ssh-ed25519 r+nK/Q mksHDhPoKKxQpk4sQPHapdq87EaJmgdmoVxMYjsAang
|
-> ssh-ed25519 r+nK/Q kgmK60IgdW4QFdKqBQ6S9JmQVoRvpmffVaoNWzfV5Bc
|
||||||
FTYHyxLp4nGOWJu1135yN/lQkGgAD9Jy4JJpMKFktrk
|
ru8etu+7QOmnAoJv8BLtEK0SuDfhB75l525ORrDirvM
|
||||||
-> ssh-rsa krWCLQ
|
-> ssh-rsa krWCLQ
|
||||||
jEPt5eWP6NmpOikLhs1uPVo7kxHgg1y7WwdOPyR0z2vpFD2BWGlIi/BvnlE3OO5n
|
QsgW7OvOB3cOz9MZI1PQ6Fe208WS+Sv/TWcucjD9i28U6Bty1KYeSwMH/zyzLuSe
|
||||||
jtvDjAauWU0X2JarfdY9mY8MoPjT9qQ/ukxuVAHi5CoL/I1JCqcbuftssYY0B7Ab
|
51TqJTnkb+xGcqw3RvKiM58HMFcl6INmOI8otGxfCQSX7p3/QxiGQBbIgRblxtWB
|
||||||
SMfbyxjK8aIT1/4EQhMoWm0tuIylvgTBagL03Lw5mbyRqDkbpI/6YC9401YjT7Ts
|
8Jf55hgfh+1+vwTcM+BlBRWz4K581MeQiF2jj6ihfJNwTZ7Q9jNvgzF42znEyZyE
|
||||||
dCDGIFAYM2BA7TuJiZr881ypUdU9rlm5rss1ZLMj90jyJPJC4SDYbzE0BoBat9l0
|
QTHoR9ROA/HqLgcrui1L7QnBlP1Y9Bt/oMCh4jFwHfcc6NeHF+I6AEeQNAHH9iNX
|
||||||
dYUrYGhGgZ1cDd6D6mPf6H95muiGHIhxaE8c+LdK/rKCSH9Rf6mfn/Ab/xvnaDNn
|
2+1RsJnQrTM+H204GrpVK78e1B5uCjvq/LeoWSQ3pFD9PwdM6JW2WfkB4FSCriAI
|
||||||
GW/WD0EpmdzpWVPby68+KA
|
7ZAg64qNahyjX+J+KDlrwQ
|
||||||
-> ssh-ed25519 /vwQcQ 5DoMxdoK+KiHXKwwOpb7/1FZIEzAa/2/1l8yyxey6iw
|
-> ssh-ed25519 /vwQcQ MBPiBQdz65VVKMxJDlTCFUfG084K0ZcGpPJc5RKKND4
|
||||||
RzmUkqZQLM5/jDXG9fxhZmfAywgVMjH9Y3O66BnhCSQ
|
jH9fRJ/tcGQpZQ+pGNw9lXcRbPS8LLsuwe4EUsaFGDM
|
||||||
-> ssh-ed25519 0R97PA g+uW/jfwHB3m0AdWxb9vPRjeaowhEx1Uoc2R0CVStlA
|
-> ssh-ed25519 0R97PA bvY5a3GO1CfVmCPJwBfFGJcS+Zkr2QRENa0WyzqspGc
|
||||||
m5XvSEVQ8DiA7BSTsxVn6S1zv92CpbyZxSgUI3ObE4c
|
YgxthAE4TIPlweuH8cWaOmVGqomc2yfLdzjO8G8bytw
|
||||||
-> ssh-ed25519 JGx7Ng BtdJpskbfPyywYeFbmQw3HGPTLv5ri6x4bFocr9l6H8
|
-> ssh-ed25519 JGx7Ng 11We2girRvmkDm8eWkTZnazm7Ly0tmECFTdSFnBKIQQ
|
||||||
88aFw+MCJLqMU/W/ikYDUZEAi0ImaPVbSc7cAZPbs/I
|
VQ+jlP1sk+SPkHARgAly9U7W0HVbpvZvxLN4V5l6JwE
|
||||||
-> ssh-ed25519 5SY7Kg +JUMQfaxl7Orym43LVeqUyno0JfUbVnB+xv7smpdRhE
|
-> ssh-ed25519 bUjjig Zt2Br6ls9INAJ5aQZ/az+6+rIpDCf/NCJP2zusdggms
|
||||||
6K+Ewq1FhrXB2eYdljlsYpIfmVv49E4jSBsphgDpRJk
|
3k0NOSVDpbQFEflEvyTzKv1/zXUBVN5ub9jjOe4EybM
|
||||||
-> ssh-ed25519 p/Mg4Q AITnEN+Q41fEA2tkvVOKGCDZiuCXanG+qaiF5X4ukiA
|
-> ssh-ed25519 +mFdtQ inTgQzJVaYt8JZjtrjVzZzW9PscvBnZWkXIpEQYtdFI
|
||||||
NvP/HXOliNvi8tngH9PU90E616CPlh/QgkZ052H8wtk
|
O/Z7ccZam386C6r2UVJS+OMwG8nZ57RmUy+VJEgWJEY
|
||||||
-> ssh-ed25519 +mFdtQ RuaXIQNZ3s9C27XtpVTExJlAhYDYXRQni+Hwot0wrzU
|
-> ssh-ed25519 5rrg4g ApGMepP+32epekSxCfLGJs6uI38WPjWxtdk+q1Lvx0I
|
||||||
WctqqoGS2hVfOZSU3ihCg5eI7PnxM7dkOJKM9DJ90Wk
|
huEBiiNzTcz5hPUs+INfDyfeqKtl+mYE38PUizHktyI
|
||||||
-> ssh-ed25519 5rrg4g cAqJQ8z6T46YwzahtcTJxXZHklCGrupVCja5U/g+ZmM
|
-> ssh-ed25519 oRtTqQ QBBeZ0kLMPuDmO0hT7LvMs31WuVZATUSyxtCxgMzHgQ
|
||||||
wERu5T6rOi5/0qPSXeOnfA0Szg7/pbYFTW0Ys1yWq40
|
HooCKv78+xzYnOwaYXbRNVH1XpG1e8tY0PB246nkFU8
|
||||||
-> ssh-ed25519 oRtTqQ NF73c0d1qM4nVt2bEdWTEDjDcz/ZMCObn/7cDZfkVGA
|
-> G8<-grease
|
||||||
Mivm+WWVqAfNs5pLwGmINIsmxlEZi7m7bQIRxGkf3/Q
|
58RFQqg54Xu8pavoh6wbEnJl7J8XJ5rgaVq1bxokhQ
|
||||||
--- 8R1h+xsovrLq+5QI1CoTXc9TBTQugnROZpOAHWBwG1w
|
--- +gYhV/IjEqBw3YKDEeSbepgAIIO6A/BcpsYrwCy+Ezs
|
||||||
G“Þ"û¤‡ã8ƒÈî‚&NF}x£ksyÖ\£.i§<69>קF¢‹¯}ê-ÍÁÓšLbì;{
|
萠%C7図殤チx盟~YヨワZチ{儖情リM<EFBE98>Hハ<48>欷ソXセ<58>ナk@モ9<EFBE93>
|
|
@ -14,19 +14,77 @@
|
||||||
# deployment = {}; # Colmena deployment options
|
# deployment = {}; # Colmena deployment options
|
||||||
# nixpkgs = "unstable" or "22.11"; # nixpkgs version
|
# nixpkgs = "unstable" or "22.11"; # nixpkgs version
|
||||||
# }
|
# }
|
||||||
|
let
|
||||||
|
nix-lib = import ../../lib/nix-lib;
|
||||||
|
inherit (nix-lib) mapFuse;
|
||||||
|
|
||||||
{
|
mkAP' = building: floor: ap-no: {
|
||||||
ap01 = {
|
"ap-v01-${builtins.toString building}-${builtins.toString floor}-${builtins.toString ap-no}" = {
|
||||||
site = "unknown";
|
site = "unknown";
|
||||||
adminGroups = [ "fai" ];
|
adminGroups = [ "fai" ];
|
||||||
|
|
||||||
hashedPassword = "$y$j9T$DMOQEWOYFHjNS0myrXp4x/$MG33VSdXGvib.99eN.AbvyVdNNJw4ERjAwK4.ULJe/A";
|
hashedPassword = "$y$j9T$DMOQEWOYFHjNS0myrXp4x/$MG33VSdXGvib.99eN.AbvyVdNNJw4ERjAwK4.ULJe/A";
|
||||||
|
|
||||||
stateVersion = null;
|
stateVersion = null;
|
||||||
|
|
||||||
nixpkgs = {
|
nixpkgs = {
|
||||||
system = "zyxel-nwa50ax";
|
system = "zyxel-nwa50ax";
|
||||||
version = "24.05";
|
version = "24.05";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraNodeSettings = {
|
||||||
|
inherit building floor ap-no;
|
||||||
|
vendor-mac = null;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
/*
|
||||||
|
Generate all APs nodes for a building. It takes a building definition and returns
|
||||||
|
an attributes set containing all nodes of the AP for the building.
|
||||||
|
|
||||||
|
Building definition:
|
||||||
|
* building-no is the index of the building
|
||||||
|
* floors is the range {from, to{ of floors that contains an AP
|
||||||
|
* ap-nos is the range [from, to{ of AP numbers
|
||||||
|
|
||||||
|
Type: AttrSet -> AttrSet
|
||||||
|
*/
|
||||||
|
mkAPs-building =
|
||||||
|
{
|
||||||
|
building-no,
|
||||||
|
floors,
|
||||||
|
ap-nos,
|
||||||
|
}:
|
||||||
|
mapFuse (f: mapFuse (mkAP' building-no f) (mkRange ap-nos)) (mkRange floors);
|
||||||
|
|
||||||
|
APs = {
|
||||||
|
hypnos-1 = {
|
||||||
|
building-no = 0;
|
||||||
|
floors = {
|
||||||
|
from = 0;
|
||||||
|
to = 3;
|
||||||
|
};
|
||||||
|
ap-nos = {
|
||||||
|
from = 1;
|
||||||
|
to = 7;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
hypnos-2 = {
|
||||||
|
building-no = 1;
|
||||||
|
floors = {
|
||||||
|
from = 0;
|
||||||
|
to = 3;
|
||||||
|
};
|
||||||
|
ap-nos = {
|
||||||
|
from = 1;
|
||||||
|
to = 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkRange = { from, to }: builtins.genList (x: x + from) (to - from);
|
||||||
|
in
|
||||||
|
{ }
|
||||||
|
// builtins.foldl' (nodes: building: nodes // mkAPs-building building) { } (builtins.attrValues APs)
|
||||||
|
|
|
@ -210,6 +210,12 @@ in
|
||||||
default = null;
|
default = null;
|
||||||
description = "VM cluster where the VM is located";
|
description = "VM cluster where the VM is located";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extraNodeSettings = mkOption {
|
||||||
|
type = attrs;
|
||||||
|
default = { };
|
||||||
|
description = "Freeform attribute set to customize the node";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
|
|
@ -153,10 +153,10 @@
|
||||||
"type": "Git",
|
"type": "Git",
|
||||||
"url": "https://git.dgnum.eu/DGNum/liminix"
|
"url": "https://git.dgnum.eu/DGNum/liminix"
|
||||||
},
|
},
|
||||||
"branch": "main",
|
"branch": "mdebray/usteer",
|
||||||
"revision": "1322de1ee0cdb19fead79e12ab279ee0b575019a",
|
"revision": "420b1764c5b5b91c3ddada6dec9bc594847b3cc5",
|
||||||
"url": null,
|
"url": null,
|
||||||
"hash": "07nk6nik97k8a57cf17dcj3gn2lbhw1myymrxpqc2aqa3haj754k"
|
"hash": "168qhll6qw5x9v9300mizpshhgmsvvwzp6786z7l1s3jqk3ygf6d"
|
||||||
},
|
},
|
||||||
"linkal": {
|
"linkal": {
|
||||||
"type": "Git",
|
"type": "Git",
|
||||||
|
|
13
scripts/export_secret.sh
Executable file
13
scripts/export_secret.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 Maurice Debray <maurice.debray@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
DECRYPT=()
|
||||||
|
if [ -f "$HOME/.ssh/id_rsa" ]; then
|
||||||
|
DECRYPT+=(-i "$HOME/.ssh/id_rsa")
|
||||||
|
fi
|
||||||
|
if [ -f "$HOME/.ssh/id_ed25519" ]; then
|
||||||
|
DECRYPT+=(-i "$HOME/.ssh/id_ed25519")
|
||||||
|
fi
|
||||||
|
|
||||||
|
export RADIUS_SECRET=$(rage "${DECRYPT[@]}" -d ./machines/nixos/vault01/secrets/radius-ap-radius-secret_file)
|
16
scripts/extract-firmware-from-zyxel-nwa-fit.sh
Executable file
16
scripts/extract-firmware-from-zyxel-nwa-fit.sh
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p ubootTools
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "extract the firmware part to write it manually from a Zyxel NWA FIT image"
|
||||||
|
echo "$0 <zyxel_nwa_fit_image_path> <firmware_output_file>"
|
||||||
|
}
|
||||||
|
|
||||||
|
ZYXEL_NWA_FIT="$1"
|
||||||
|
FIRMWARE_OUTPUT="$2"
|
||||||
|
|
||||||
|
dumpimage -T flat_dt -p 0 $ZYXEL_NWA_FIT -o $FIRMWARE_OUTPUT
|
35
scripts/ftp_zeroday.sh
Executable file
35
scripts/ftp_zeroday.sh
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -p inetutils -i bash
|
||||||
|
# SPDX-FileCopyrightText: 2024 Maurice Debray <maurice.debray@dgnum.eu>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
#
|
||||||
|
# Tribute to RaitoBezarius for finding the exploit
|
||||||
|
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "./ftp_zeroday.sh [FIT-IMAGE] [IP]"
|
||||||
|
}
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! [ -e "$1" ]; then
|
||||||
|
echo "$1 not found" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE="$1"
|
||||||
|
IP="$2"
|
||||||
|
|
||||||
|
echo "Trying to flash $IMAGE to $IP..."
|
||||||
|
|
||||||
|
# TODO: make it exit cleanly
|
||||||
|
ftp -niv <<EOF
|
||||||
|
open $IP
|
||||||
|
user admin 1234
|
||||||
|
binary
|
||||||
|
put $IMAGE
|
||||||
|
EOF
|
||||||
|
|
58
scripts/liminix-rebuild.sh
Executable file
58
scripts/liminix-rebuild.sh
Executable file
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2024 Daniel Barlow <dan@telent.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
# TODO: support automatic levitation when the rebuild counts does not fit in the target.
|
||||||
|
# TODO: support preflight checks where we detect the environment we are booted in (this requires the levitation to write a special file).
|
||||||
|
# TODO: use colmena to know the target host and focus on the node name.
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
ssh_command=${SSH_COMMAND-ssh}
|
||||||
|
root_prefix=${ROOT_PREFIX-/}
|
||||||
|
|
||||||
|
reboot="reboot"
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"--no-reboot")
|
||||||
|
unset reboot
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
"--fast")
|
||||||
|
reboot="soft"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
"--live")
|
||||||
|
echo "Root prefix changed from $root_prefix to /mnt"
|
||||||
|
root_prefix="/mnt"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
target_host=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ -z "$target_host" ] ; then
|
||||||
|
echo Usage: liminix-rebuild \[--no-reboot\] target-host params
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if toplevel="$(nom-build $(colmena eval -E "{ nodes, ... }: nodes.$@.config.system.outputs.systemConfiguration" --instantiate))"; then
|
||||||
|
echo systemConfiguration $toplevel aimed at $root_prefix
|
||||||
|
sleep 3
|
||||||
|
min-copy-closure --root "$root_prefix" $target_host $toplevel
|
||||||
|
$ssh_command $target_host "$root_prefix/$toplevel/bin/install" "$root_prefix"
|
||||||
|
case "$reboot" in
|
||||||
|
reboot)
|
||||||
|
$ssh_command $target_host "sync; source /etc/profile; reboot"
|
||||||
|
;;
|
||||||
|
soft)
|
||||||
|
$ssh_command $target_host $toplevel/bin/restart-services
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo Rebuild failed
|
||||||
|
fi
|
Loading…
Add table
Reference in a new issue